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
893 changes: 298 additions & 595 deletions js/package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
"@aztec/bb-prover": "3.0.0-devnet.2",
"@aztec/noir-contracts.js": "3.0.0-devnet.2",
"@aztec/pxe": "3.0.0-devnet.2",
"@aztec/test-wallet": "^3.0.0-devnet.2",
"@aztec/test-wallet": "3.0.0-devnet.2",
"@temporalio/worker": "^1.12.1",
"@nestjs/common": "11.1.2",
"@nestjs/config": "^4.0.2",
"axios": "^1.11.0",
"dotenv": "^16.4.7",
"ethers": "^5.8.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import Redis from 'ioredis';
import Redlock from 'redlock';
import { container } from 'tsyringe';
import { ConvertToRedisUrl } from './RedisHelper/RedisFactory';
import { PrivateKeyService } from '../../Blockchain.Aztec/KeyVault/vault.service';
import { PrivateKeyConfigService } from '../../Blockchain.Aztec/KeyVault/vault.config';
import { AztecConfigService } from '../../Blockchain.Aztec/KeyVault/aztec.config';

export async function AddCoreServices(): Promise<void> {

Expand All @@ -13,7 +16,18 @@ export async function AddCoreServices(): Promise<void> {
retryDelay: 200,
retryJitter: 100,
});
const configService = {
get: (key: string) => process.env[key]
};

const privateKeyConfigService = new PrivateKeyConfigService(configService as any);
const privateKeyService = new PrivateKeyService();

privateKeyService.init(privateKeyConfigService);
const aztecConfigService = new AztecConfigService(configService as any);

container.register<Redlock>("Redlock", { useValue: redlock });
container.register<Redis>("Redis", { useValue: redis });
container.register<PrivateKeyService>("PrivateKeyService", { useValue: privateKeyService });
container.register<AztecConfigService>("AztecConfigService", { useValue: aztecConfigService });
}
7,352 changes: 3,582 additions & 3,770 deletions js/src/Blockchain/Blockchain.Aztec/Activities/ABIs/train.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ import TrackBlockEventsAsync from "./Helper/AztecEventTracker";
import { createRefundCallData, createLockCallData, createRedeemCallData, createCommitCallData } from "./Helper/AztecTransactionBuilder";
import { TransactionFailedException } from "../../Blockchain.Abstraction/Exceptions/TransactionFailedException";
import { Tx, TxHash } from "@aztec/aztec.js/tx";
import { createAztecNodeClient } from '@aztec/aztec.js/node';
import { mapAztecStatusToInternal } from "./Helper/AztecTransactionStatusMapper";
import { AztecPublishTransactionRequest } from "../Models/AztecPublishTransactionRequest";
import { TreasuryClient } from "../../Blockchain.Abstraction/Infrastructure/TreasuryClient/treasuryClient";
import { AztecSignTransactionRequestModel } from "./Models/AztecSignTransactionModel";
import { buildLockKey as buildLockKey, buildCurrentNonceKey, buildNextNonceKey } from "../../Blockchain.Abstraction/Infrastructure/RedisHelper/RedisHelper";
import { NextNonceRequest } from "../../Blockchain.Abstraction/Models/NonceModels/NextNonceRequest";
Expand All @@ -29,12 +27,34 @@ import Redis from "ioredis";
import Redlock from "redlock";
import { TimeSpan } from "../../Blockchain.Abstraction/Infrastructure/RedisHelper/TimeSpanConverter";
import { TransactionNotComfirmedException } from "../../Blockchain.Abstraction/Exceptions/TransactionNotComfirmedException";
import { TrainContract } from "./Helper/Train";
import { PrivateKeyService } from '../KeyVault/vault.service';
import { ContractFunctionInteraction, getContractInstanceFromInstantiationParams, toSendOptions } from '@aztec/aztec.js/contracts';
import { SponsoredFeePaymentMethod } from '@aztec/aztec.js/fee';
import { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC';
import { TestWallet } from '@aztec/test-wallet/server';
import { createStore } from '@aztec/kv-store/lmdb';
import { AztecNode, createAztecNodeClient } from '@aztec/aztec.js/node';
import { getPXEConfig } from '@aztec/pxe/server';
import { Fr } from '@aztec/aztec.js/fields';
import { deriveSigningKey } from '@aztec/stdlib/keys';
import { AztecAddress } from '@aztec/aztec.js/addresses';
import { TokenContract } from '@aztec/noir-contracts.js/Token';
import { AuthWitness } from '@aztec/stdlib/auth-witness';
import { ContractFunctionInteractionCallIntent } from '@aztec/aztec.js/authorization';
import { ContractArtifact, FunctionAbi, getAllFunctionAbis } from '@aztec/aztec.js/abi';
import { SchnorrAccountContract } from '@aztec/accounts/schnorr';
import { getAccountContractAddress } from '@aztec/aztec.js/account';
import { AztecFunctionInteractionModel } from "./Models/AztecFunctionInteractionModel";
import { AztecConfigService } from "../KeyVault/aztec.config";

@injectable()
export class AztecBlockchainActivities implements IAztecBlockchainActivities {
constructor(
@inject("Redis") private redis: Redis,
@inject("Redlock") private lockFactory: Redlock,
@inject("PrivateKeyService") private privateKeyService: PrivateKeyService,
@inject("AztecConfigService") private aztecConfigService: AztecConfigService,
) { }

public async BuildTransaction(request: TransactionBuilderRequest): Promise<PrepareTransactionResponse> {
Expand Down Expand Up @@ -114,12 +134,137 @@ export class AztecBlockchainActivities implements IAztecBlockchainActivities {
}

public async signTransaction(request: AztecSignTransactionRequestModel): Promise<string> {
try {
const privateKey = await this.privateKeyService.getAsync(request.solverAddress);
const privateSalt = await this.privateKeyService.getAsync(request.solverAddress, "private_salt");
const provider: AztecNode = createAztecNodeClient(request.nodeUrl);
const l1Contracts = await provider.getL1ContractAddresses();

const fullConfig = { ...getPXEConfig(), l1Contracts, proverEnabled: true };

const accountContract = new SchnorrAccountContract(deriveSigningKey(Fr.fromString(privateKey)));
const solverAddress = (await getAccountContractAddress(accountContract, Fr.fromString(privateKey), Fr.fromString(privateSalt))).toString();

const store = await createStore(request.solverAddress, {
dataDirectory: this.aztecConfigService.storePath,
dataStoreMapSizeKb: 1e6,
});

const pxe = await TestWallet.create(provider, fullConfig, { store });

const sponsoredFPCInstance = await getContractInstanceFromInstantiationParams(
SponsoredFPCContract.artifact,
{ salt: new Fr(0) },
);

await pxe.registerContract(
sponsoredFPCInstance,
SponsoredFPCContract.artifact,
);

await pxe.createSchnorrAccount(
Fr.fromString(privateKey),
Fr.fromString(privateSalt),
deriveSigningKey(Fr.fromString(privateKey)),
);

const contractInstanceWithAddress = await provider.getContract(AztecAddress.fromString(request.contractAddress));
await pxe.registerContract(contractInstanceWithAddress, TrainContract.artifact);

const tokenInstance = await provider.getContract(AztecAddress.fromString(request.tokenContract));
await pxe.registerContract(tokenInstance, TokenContract.artifact)

const contractFunctionInteraction: AztecFunctionInteractionModel = JSON.parse(request.unsignedTxn);
let authWitnesses: AuthWitness[] = [];

if (contractFunctionInteraction.authwiths) {
for (const authWith of contractFunctionInteraction.authwiths) {
const requestContractClass = await provider.getContract(AztecAddress.fromString(authWith.interactionAddress));
const contractClassMetadata = await pxe.getContractClassMetadata(requestContractClass.currentContractClassId, true);

if (!contractClassMetadata.artifact) {
throw new Error(`Artifact not registered`);
}

const functionAbi = getFunctionAbi(contractClassMetadata.artifact, authWith.functionName);

if (!functionAbi) {
throw new Error("Unable to get function ABI");
}

authWith.args.unshift(solverAddress);

const treasuryClient = new TreasuryClient(request.signerAgentUrl);
const functionInteraction = new ContractFunctionInteraction(
pxe,
AztecAddress.fromString(authWith.interactionAddress),
functionAbi,
[...authWith.args],
);

const response = await treasuryClient.signTransaction(request.networkType, request.signRequest);
const intent: ContractFunctionInteractionCallIntent = {
caller: AztecAddress.fromString(authWith.callerAddress),
action: functionInteraction,
};

return response.signedTxn;
const witness = await pxe.createAuthWit(
AztecAddress.fromString(solverAddress),
intent,
);

authWitnesses.push(witness);
}
}

const requestcontractClass = await provider.getContract(AztecAddress.fromString(contractFunctionInteraction.interactionAddress))
const contractClassMetadata = await pxe.getContractClassMetadata(requestcontractClass.currentContractClassId, true)

if (!contractClassMetadata.artifact) {
throw new Error(`Artifact not registered`);
}

const functionAbi = getFunctionAbi(contractClassMetadata.artifact, contractFunctionInteraction.functionName);

const functionInteraction = new ContractFunctionInteraction(
pxe,
AztecAddress.fromString(contractFunctionInteraction.interactionAddress),
functionAbi,
[
...contractFunctionInteraction.args
],
[...authWitnesses]
);

const executionPayload = await functionInteraction.request({
authWitnesses: [...authWitnesses],
fee: { paymentMethod: new SponsoredFeePaymentMethod(sponsoredFPCInstance.address) },
});

var sendOptions = await toSendOptions(
{
from: AztecAddress.fromString(request.solverAddress),
authWitnesses: [...authWitnesses],
fee: { paymentMethod: new SponsoredFeePaymentMethod(sponsoredFPCInstance.address) },
},
);

const provenTx = await pxe.proveTx(executionPayload, sendOptions);

const tx = new Tx(
provenTx.getTxHash(),
provenTx.data,
provenTx.clientIvcProof,
provenTx.contractClassLogFields,
provenTx.publicFunctionCalldata,
);

const signedTxHex = tx.toBuffer().toString("hex");
const signedTxn = JSON.stringify({ signedTx: signedTxHex });

return signedTxn;
}
catch (error) {
throw new Error(`Error while signing transaction: ${error.message}`);
}
}

public async publishTransaction(request: AztecPublishTransactionRequest): Promise<string> {
Expand Down Expand Up @@ -208,3 +353,12 @@ export class AztecBlockchainActivities implements IAztecBlockchainActivities {
throw new Error("Method not implemented.");
}
}

function getFunctionAbi(
artifact: ContractArtifact,
fnName: string,
): FunctionAbi | undefined {
const fn = getAllFunctionAbis(artifact).find(({ name }) => name === fnName);
if (!fn) { }
return fn;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Fr } from '@aztec/foundation/fields';
import { PrepareTransactionResponse } from "../../../Blockchain.Abstraction/Models/TransactionBuilderModels/TransferBuilderResponse";
import crypto from 'crypto';
import { TransferPrepareRequest } from "../../../Blockchain.Abstraction/Models/TransactionBuilderModels/TransferPrepareRequest";
import { AztecFunctionInteractionModel } from "../Models/AztecFunctionInteractionModel";

export async function createRefundCallData(network: DetailedNetworkDto, args: string): Promise<PrepareTransactionResponse> {

Expand All @@ -23,7 +24,7 @@ export async function createRefundCallData(network: DetailedNetworkDto, args: st
? network.htlcNativeContractAddress
: network.htlcTokenContractAddress;

let functionInteraction: FunctionInteraction = {
let functionInteraction: AztecFunctionInteractionModel = {
interactionAddress: htlcContractAddress,
functionName: "refund_private",
args: [refundRequest.commitId],
Expand Down Expand Up @@ -54,7 +55,7 @@ export async function createCommitCallData(network: DetailedNetworkDto, args: st

const randomness = BigInt('0x' + crypto.randomBytes(31).toString('hex')).toString()

let functionInteraction: FunctionInteraction = {
let functionInteraction: AztecFunctionInteractionModel = {
interactionAddress: htlcContractAddress,
functionName: "commit_private_user",
args: [
Expand Down Expand Up @@ -107,7 +108,7 @@ export async function createRedeemCallData(network: DetailedNetworkDto, args: st
const [secretHigh, secretLow] = hexToU128Limbs(toHex((BigInt(redeemRequest.secret))));
const [ownershipKeyHigh, ownershipKeyLow] = hexToU128Limbs(toHex(BigInt(redeemRequest.secret)));

let functionInteraction: FunctionInteraction = {
let functionInteraction: AztecFunctionInteractionModel = {
interactionAddress: htlcContractAddress,
functionName: "redeem_private",
args: [
Expand Down Expand Up @@ -147,7 +148,7 @@ export async function createLockCallData(network: DetailedNetworkDto, args: stri
const hashlock = hexToU128Limbs(lockRequest.hashlock);
const ownershipHash = hexToU128Limbs(normalizeHex(lockRequest.receiver));

let functionInteraction: FunctionInteraction = {
let functionInteraction: AztecFunctionInteractionModel = {
interactionAddress: htlcContractAddress,
functionName: "lock_private_solver",
args: [
Expand Down Expand Up @@ -195,7 +196,7 @@ export async function createTransferCallData(network: DetailedNetworkDto, args:
throw new Error(`Token not found for network ${network.name} and asset ${transferRequest.asset}`)
};

let functionInteraction: FunctionInteraction = {
let functionInteraction: AztecFunctionInteractionModel = {
interactionAddress: token.contract,
functionName: "transfer",
args: [
Expand All @@ -214,14 +215,6 @@ export async function createTransferCallData(network: DetailedNetworkDto, args:
};
}

interface FunctionInteraction {
interactionAddress: string,
functionName: string,
args: any[],
callerAddress?: string,
authwiths?: FunctionInteraction[],
}

export const hexToUint256HexStrings = (hex: string): string[] => {
let h = hex.startsWith('0x') ? hex.slice(2) : hex;
if (h.length % 2) h = '0' + h;
Expand Down
Loading