o1js
Version:
TypeScript framework for zk-SNARKs and zkApps
113 lines (98 loc) • 4.05 kB
text/typescript
import { ZkappCommand } from '../../bindings/mina-transaction/gen/v1/transaction-bigint.js';
import * as TransactionJson from '../../bindings/mina-transaction/gen/v1/transaction-json.js';
import Client from '../mina-signer.js';
import { accountUpdateExample } from '../src/test-vectors/accountUpdate.js';
import { expect } from 'expect';
import { Transaction } from '../../lib/mina/v1/mina.js';
import { PrivateKey } from '../../lib/provable/crypto/signature.js';
import { Signature } from '../src/signature.js';
import { mocks } from '../../bindings/crypto/constants.js';
const client = new Client({ network: 'devnet' });
let { publicKey, privateKey } = client.genKeys();
let dummy = ZkappCommand.toJSON(ZkappCommand.empty());
let dummySignature = Signature.toBase58(Signature.dummy());
// we construct a transaction which needs signing of the fee payer and another account update
let accountUpdateExample2: TransactionJson.AccountUpdate = {
...accountUpdateExample,
body: {
...accountUpdateExample.body,
publicKey,
authorizationKind: {
isSigned: true,
isProved: false,
verificationKeyHash: mocks.dummyVerificationKeyHash,
},
},
authorization: { proof: null, signature: dummySignature },
};
let exampleZkappCommand: TransactionJson.ZkappCommand = {
...dummy,
accountUpdates: [accountUpdateExample, accountUpdateExample2],
memo: 'E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH',
};
let exampleFeePayer = {
feePayer: publicKey,
fee: '100000000',
nonce: '1',
memo: 'test memo',
};
// generates and verifies a signed zkapp command
let zkappCommand = client.signZkappCommand(
{ zkappCommand: exampleZkappCommand, feePayer: exampleFeePayer },
privateKey
);
expect(zkappCommand.data).toBeDefined();
expect(zkappCommand.signature).toBeDefined();
expect(client.verifyZkappCommand(zkappCommand)).toEqual(true);
expect(client.verifyTransaction(zkappCommand)).toEqual(true);
// generates and verifies a signed zkapp command by using signTransaction
zkappCommand = client.signTransaction(
{ zkappCommand: exampleZkappCommand, feePayer: exampleFeePayer },
privateKey
);
expect(zkappCommand.data).toBeDefined();
expect(zkappCommand.signature).toBeDefined();
expect(client.verifyZkappCommand(zkappCommand)).toEqual(true);
expect(client.verifyTransaction(zkappCommand)).toEqual(true);
// does not verify a signed zkapp command from `mainnet`
const mainnetClient = new Client({ network: 'mainnet' });
expect(mainnetClient.verifyZkappCommand(zkappCommand)).toEqual(false);
expect(mainnetClient.verifyTransaction(zkappCommand)).toEqual(false);
// should throw an error if no fee is passed to the fee payer
expect(() => {
client.signZkappCommand(
{
zkappCommand: exampleZkappCommand,
// @ts-ignore - fee is not defined
feePayer: { feePayer: publicKey, nonce: '0', memo: 'test memo' },
},
privateKey
);
}).toThrow('Missing fee in fee payer');
// should calculate a correct minimum fee
expect(client.getAccountUpdateMinimumFee(exampleZkappCommand.accountUpdates)).toBe(0.002);
// same transaction signed with o1js (OCaml implementation) gives the same result
let transactionJson = {
...exampleZkappCommand,
feePayer: {
body: {
publicKey: exampleFeePayer.feePayer,
fee: exampleFeePayer.fee,
nonce: exampleFeePayer.nonce,
validUntil: null,
},
authorization: dummySignature,
},
memo: zkappCommand.data.zkappCommand.memo,
};
let tx = Transaction.fromJSON(transactionJson);
tx.transaction.feePayer.lazyAuthorization = { kind: 'lazy-signature' };
tx.transaction.accountUpdates[1].lazyAuthorization = { kind: 'lazy-signature' };
tx.sign([PrivateKey.fromBase58(privateKey)]);
expect(zkappCommand.data.zkappCommand.feePayer.authorization).toEqual(
tx.transaction.feePayer.authorization
);
expect(zkappCommand.data.zkappCommand.accountUpdates[1].authorization.signature).toEqual(
tx.transaction.accountUpdates[1].authorization.signature
);
expect(JSON.stringify(zkappCommand.data.zkappCommand)).toEqual(tx.toJSON());