Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add send API to zkApp and Party classes #325

Merged
merged 5 commits into from
Aug 4, 2022
Merged
Show file tree
Hide file tree
Changes from 4 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
131 changes: 131 additions & 0 deletions src/examples/simple-zkapp-payment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import {
Copy link
Contributor

Choose a reason for hiding this comment

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

@MartinMinkov @mitschabaude do you have an opinion if we should be adding examples like these in the src/examples/zkapps directory or keep them in src/examples? I noticed apps like composability and simple_and_counter were added to the zkapps directory and others to examples. It's not a big deal either way as long as we are in agreement.

Copy link
Contributor

Choose a reason for hiding this comment

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

good point, I think we'll accumulate more & more of those, so I'd add most of them to /src/examples/zkapps and reserve /src/examples for the most fundamental examples, to not overwhelm a user who explores these

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure thing, I'll move it over

isReady,
method,
Mina,
Party,
PrivateKey,
SmartContract,
PublicKey,
UInt64,
shutdown,
DeployArgs,
Permissions,
} from 'snarkyjs';

await isReady;

class SendMINAExample extends SmartContract {
deploy(args: DeployArgs) {
super.deploy(args);
this.setPermissions({
...Permissions.default(),
editState: Permissions.proofOrSignature(),
editSequenceState: Permissions.proofOrSignature(),
});
this.balance.addInPlace(UInt64.fromNumber(initialBalance));
}

@method sendMINA(receiverAddress: PublicKey, amount: UInt64) {
this.send({
to: receiverAddress,
amount,
});
}
}

let Local = Mina.LocalBlockchain();
Mina.setActiveInstance(Local);

// a test account that pays all the fees, and puts additional funds into the zkapp
let feePayer = Local.testAccounts[0].privateKey;

// the zkapp account
let zkappKey = PrivateKey.random();
let zkappAddress = zkappKey.toPublicKey();

let account1Key = PrivateKey.random();
let account1Address = account1Key.toPublicKey();

let account2Key = PrivateKey.random();
let account2Address = account2Key.toPublicKey();

let zkapp = new SendMINAExample(zkappAddress);
let initialBalance = 10_000_000_000;
let tx;

console.log('deploy');
tx = await Mina.transaction(feePayer, () => {
Party.fundNewAccount(feePayer, { initialBalance });
zkapp.deploy({ zkappKey });
});
tx.send();

console.log(`zkApp balance: ${Mina.getBalance(zkappAddress)} MINA`);

console.log('----------MINA sending----------');
tx = await Local.transaction(feePayer, () => {
Party.fundNewAccount(feePayer);
zkapp.sendMINA(account1Address, UInt64.from(1_000_000));
zkapp.sign(zkappKey);
});
tx.send();

console.log(`zkApp balance: ${Mina.getBalance(zkappAddress)} MINA`);
console.log(
`account1Address balance: ${Mina.getBalance(account1Address)} MINA`
);

console.log('----------MINA sending (with signed)----------');
tx = await Local.transaction(feePayer, () => {
Party.fundNewAccount(feePayer);
let party = Party.createSigned(zkappKey);
party.send({ to: account2Address, amount: UInt64.from(1_000_000) });
zkapp.sign(zkappKey);
zkapp.account.nonce.assertEquals(zkapp.account.nonce.get().add(1));
});
tx.send();

console.log(`zkApp balance: ${Mina.getBalance(zkappAddress)} MINA`);
console.log(
`account1Address balance: ${Mina.getBalance(account1Address)} MINA`
);
console.log(
`account2Address balance: ${Mina.getBalance(account2Address)} MINA`
);

console.log('----------MINA sending (with unsigned)----------');
tx = await Local.transaction(feePayer, () => {
let party = Party.createUnsigned(zkappAddress);
party.signInPlace(zkappKey);
party.send({ to: account2Address, amount: UInt64.from(1_000_000) });
zkapp.sign(zkappKey);
zkapp.account.nonce.assertEquals(zkapp.account.nonce.get().add(1));
});
tx.send();

console.log(`zkApp balance: ${Mina.getBalance(zkappAddress)} MINA`);
console.log(
`account1Address balance: ${Mina.getBalance(account1Address)} MINA`
);
console.log(
`account2Address balance: ${Mina.getBalance(account2Address)} MINA`
);

console.log('----------MINA sending (with proof)----------');
tx = await Local.transaction(feePayer, () => {
let party = Party.createSigned(zkappKey);
party.send({ to: account2Address, amount: UInt64.from(1_000_000) });
zkapp.account.nonce.assertEquals(zkapp.account.nonce.get().add(1));
});
await tx.prove();
tx.send();

console.log(`zkApp balance: ${Mina.getBalance(zkappAddress)} MINA`);
console.log(
`account1Address balance: ${Mina.getBalance(account1Address)} MINA`
);
console.log(
`account2Address balance: ${Mina.getBalance(account2Address)} MINA`
);

shutdown();
19 changes: 19 additions & 0 deletions src/lib/party.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export {
Token,
CallForest,
createChildParty,
SendParams,
};

const ZkappStateLength = 8;
Expand Down Expand Up @@ -670,6 +671,24 @@ class Party implements Types.Party {
};
}

send({ to, amount }: Omit<SendParams, 'from'>) {
let party = this;
let receiverParty = createChildParty(party, to, {
tokenId: party.body.tokenId,
caller: party.body.tokenId,
});

// Sub the amount from the sender's account
let i0 = party.body.balanceChange;
party.body.balanceChange = new Int64(i0.magnitude, i0.sgn).sub(amount);

// Add the amount to send to the receiver's account
let i1 = receiverParty.body.balanceChange;
receiverParty.body.balanceChange = new Int64(i1.magnitude, i1.sgn).add(
amount
);
}

get balance() {
let party = this;

Expand Down
12 changes: 8 additions & 4 deletions src/lib/token.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class TokenContract extends SmartContract {
});
}

@method send(
@method sendTokens(
senderAddress: PublicKey,
receiverAddress: PublicKey,
amount: UInt64
Expand Down Expand Up @@ -253,7 +253,7 @@ describe('Token', () => {
(
await Mina.transaction(feePayer, () => {
Party.fundNewAccount(feePayer);
zkapp.send(tokenAccount1, tokenAccount2, UInt64.from(10_000));
zkapp.sendTokens(tokenAccount1, tokenAccount2, UInt64.from(10_000));
zkapp.sign(zkappKey);
})
)
Expand All @@ -279,7 +279,7 @@ describe('Token', () => {

let tx = (
await Mina.transaction(feePayer, () => {
zkapp.send(tokenAccount1, tokenAccount2, UInt64.from(10_000));
zkapp.sendTokens(tokenAccount1, tokenAccount2, UInt64.from(10_000));
zkapp.sign(zkappKey);
})
).sign([tokenAccount1Key]);
Expand All @@ -300,7 +300,11 @@ describe('Token', () => {

let tx = (
await Mina.transaction(feePayer, () => {
zkapp.send(tokenAccount1, tokenAccount2, UInt64.from(100_000_000));
zkapp.sendTokens(
tokenAccount1,
tokenAccount2,
UInt64.from(100_000_000)
);
zkapp.sign(zkappKey);
})
).sign([tokenAccount1Key]);
Expand Down
5 changes: 5 additions & 0 deletions src/lib/zkapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
Authorization,
CallForest,
getDefaultTokenId,
SendParams,
} from './party';
import { PrivateKey, PublicKey } from './signature';
import * as Mina from './mina';
Expand Down Expand Up @@ -562,6 +563,10 @@ class SmartContract {
return this.self.token();
}

send(args: Omit<SendParams, 'from'>) {
return this.self.send(args);
}

get tokenId() {
return this.self.tokenId;
}
Expand Down