@provablehq/sdk 0.6.10 → 0.6.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -349
- package/dist/function-key-provider.d.ts +14 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +95 -28
- package/dist/index.js.map +1 -1
- package/dist/program-manager.d.ts +4 -7
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +2 -2
- package/dist/worker.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ The Aleo SDK provides the following functionality (Click to see examples):
|
|
|
32
32
|
* [Installation](#Installation)
|
|
33
33
|
* [Usage](#Usage)
|
|
34
34
|
* [Zero-Knowledge Web App Examples](#Zero-Knowledge-Web-App-Examples)
|
|
35
|
-
* [Create
|
|
35
|
+
* [Create Leo App](#create-leo-app)
|
|
36
36
|
* [Provable.tools](#provabletools)
|
|
37
37
|
* [Create An Aleo Account](#1-create-an-aleo-account)
|
|
38
38
|
* [Execute Aleo Programs](#2-execute-aleo-programs)
|
|
@@ -68,23 +68,33 @@ To clone the repository, run:
|
|
|
68
68
|
|
|
69
69
|
To install the Aleo SDK from NPM run:
|
|
70
70
|
|
|
71
|
-
`npm install @provablehq/sdk` or `cd sdk && yarn add @provablehq/sdk`.
|
|
71
|
+
`npm install @provablehq/sdk` in your own project's root, or from within this repo run `cd sdk && yarn add @provablehq/sdk`.
|
|
72
72
|
|
|
73
73
|
### Build from source
|
|
74
74
|
|
|
75
|
-
To build the project from source, go to
|
|
75
|
+
To build the project from source, go to the project's root and execute:
|
|
76
76
|
|
|
77
77
|
`yarn build:all`
|
|
78
78
|
|
|
79
|
+
### Ensure compatibility with ES modules
|
|
80
|
+
|
|
81
|
+
In your project's `package.json`, ensure that the following line is added above `scripts`:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"type": "module",
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
79
89
|
## Getting Started: Zero-Knowledge Web App Examples
|
|
80
90
|
|
|
81
|
-
### Create
|
|
91
|
+
### Create Leo App
|
|
82
92
|
A set of fully functional examples of zero-knowledge web apps can be found in
|
|
83
|
-
[create-
|
|
93
|
+
[create-leo-app](https://github.com/ProvableHQ/sdk/tree/testnet3/create-leo-app). Create Leo App provides several web app
|
|
84
94
|
templates in common web frameworks such as React that can be used as a starting point for building zero-knowledge web apps.
|
|
85
95
|
|
|
86
|
-
Developers can get started immediately with create-
|
|
87
|
-
`npm create
|
|
96
|
+
Developers can get started immediately with create-leo-app by running:
|
|
97
|
+
`npm create leo-app@latest`
|
|
88
98
|
|
|
89
99
|
### provable.tools
|
|
90
100
|
|
|
@@ -136,12 +146,13 @@ Aleo programs provide the ability for users to make any input or output of a pro
|
|
|
136
146
|
was run correctly. Keeping program inputs and outputs private allows developers to build privacy into their applications.
|
|
137
147
|
|
|
138
148
|
Zero-knowledge programs are written in one of two languages:
|
|
139
|
-
1. [Leo](https://docs.leo-lang.org/leo/language): A high-level, developer
|
|
149
|
+
1. [Leo](https://docs.leo-lang.org/leo/language): A high-level, developer-friendly language for developing
|
|
140
150
|
zero-knowledge programs.
|
|
141
|
-
|
|
151
|
+
|
|
152
|
+
2. [Aleo Instructions](https://docs.leo-lang.org/aleo/language): A low-level language that provides developers with fine-grained control over the execution flow of zero-knowledge programs. Leo code is compiled into Aleo Instructions
|
|
142
153
|
under the hood.
|
|
143
154
|
|
|
144
|
-
Documentation for both languages can be found at [
|
|
155
|
+
Documentation for both languages can be found at [docs.leo-lang.org](https://docs.leo-lang.org/).
|
|
145
156
|
|
|
146
157
|
#### "Hello World" in Leo
|
|
147
158
|
```
|
|
@@ -158,7 +169,7 @@ program helloworld.aleo {
|
|
|
158
169
|
```
|
|
159
170
|
program helloworld.aleo;
|
|
160
171
|
|
|
161
|
-
// The
|
|
172
|
+
// The Leo code above compiles to the following Aleo Instructions:
|
|
162
173
|
function hello:
|
|
163
174
|
input r0 as u32.public;
|
|
164
175
|
input r1 as u32.private;
|
|
@@ -176,15 +187,15 @@ with JavaScript bindings that allow for the execution of Aleo programs fully wit
|
|
|
176
187
|
details on how this is achieved can visit the [aleo-wasm](https://www.npmjs.com/package/@provablehq/wasm) crate.
|
|
177
188
|
|
|
178
189
|
The basic execution flow of a program is as follows:
|
|
179
|
-
1. A web app is loaded with an instance of the `ProgramManager` object
|
|
180
|
-
2. The SDK wasm modules are loaded into the browser's WebAssembly runtime
|
|
181
|
-
2. An Aleo program in `Aleo Instructions` format is loaded into the `ProgramManager` as a wasm object
|
|
182
|
-
3. The web app provides a user input form for the program
|
|
183
|
-
4. The user submits the inputs and the zero-knowledge execution is performed entirely within the browser via WebAssembly
|
|
184
|
-
5. The result is returned to the user
|
|
185
|
-
6. A fully encrypted zero-knowledge transcript of the execution is optionally sent to the Aleo network
|
|
186
|
-
|
|
187
|
-
A diagramatic representation of the program execution flow is shown below
|
|
190
|
+
1. A web app is loaded with an instance of the `ProgramManager` object.
|
|
191
|
+
2. The SDK wasm modules are loaded into the browser's WebAssembly runtime.
|
|
192
|
+
2. An Aleo program in `Aleo Instructions` format is loaded into the `ProgramManager` as a wasm object.
|
|
193
|
+
3. The web app provides a user input form for the program.
|
|
194
|
+
4. The user submits the inputs and the zero-knowledge execution is performed entirely within the browser via WebAssembly.
|
|
195
|
+
5. The result is returned to the user.
|
|
196
|
+
6. A fully encrypted zero-knowledge transcript of the execution is optionally sent to the Aleo network.
|
|
197
|
+
|
|
198
|
+
A diagramatic representation of the program execution flow is shown below:
|
|
188
199
|
```mermaid
|
|
189
200
|
graph LR
|
|
190
201
|
p1[Leo Program]
|
|
@@ -221,9 +232,9 @@ const account = new Account();
|
|
|
221
232
|
|
|
222
233
|
### 2.4 Local program execution
|
|
223
234
|
|
|
224
|
-
A simple example of running the "hello world" program
|
|
235
|
+
A simple example of running the "hello world" program locally using Node.js and capturing its outputs is shown below:
|
|
225
236
|
```typescript
|
|
226
|
-
import { Account,
|
|
237
|
+
import { Account, ProgramManager } from '@provablehq/sdk';
|
|
227
238
|
|
|
228
239
|
/// Create the source for the "hello world" program
|
|
229
240
|
const program = "program helloworld.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n";
|
|
@@ -234,9 +245,9 @@ const account = new Account();
|
|
|
234
245
|
programManager.setAccount(account);
|
|
235
246
|
|
|
236
247
|
/// Get the response and ensure that the program executed correctly
|
|
237
|
-
const executionResponse = await programManager.
|
|
248
|
+
const executionResponse = await programManager.run(program, "hello", ["5u32", "5u32"]);
|
|
238
249
|
const result = executionResponse.getOutputs();
|
|
239
|
-
assert(result
|
|
250
|
+
assert.deepStrictEqual(result, ['10u32']);
|
|
240
251
|
```
|
|
241
252
|
|
|
242
253
|
### 2.5 Program execution on the Aleo network
|
|
@@ -244,46 +255,63 @@ The SDK provides the ability to execute programs and store an encrypted transcri
|
|
|
244
255
|
network that anyone can trustlessly verify.
|
|
245
256
|
|
|
246
257
|
This process can be thought of as being executed in the following steps:
|
|
247
|
-
1. A program is run locally
|
|
248
|
-
2. A proof that the program was executed correctly and that the outputs follow from the inputs is generated
|
|
258
|
+
1. A program is run locally.
|
|
259
|
+
2. A proof that the program was executed correctly and that the outputs follow from the inputs is generated.
|
|
249
260
|
3. A transcript of the proof is generated client-side containing encrypted proof data (see [Section 2.6](#4-managing-records-and-private-state))
|
|
250
|
-
and any public outputs or state the user of the program wishes to reveal
|
|
251
|
-
4. The proof transcript is posted to the Aleo network and verified by the Aleo validator nodes in a trustless manner
|
|
261
|
+
and any public outputs or state the user of the program wishes to reveal.
|
|
262
|
+
4. The proof transcript is posted to the Aleo network and verified by the Aleo validator nodes in a trustless manner.
|
|
252
263
|
5. If the proof is valid, it is stored and anyone can later verify the proof and read the outputs the author of the
|
|
253
264
|
program has chosen to make public. Private inputs will remain encrypted, but the author of the proof can also choose to
|
|
254
|
-
retrieve this encrypted state at any point and decrypt it locally for their own use
|
|
265
|
+
retrieve this encrypted state at any point and decrypt it locally for their own use.
|
|
255
266
|
|
|
256
267
|
Posting an execution to the Aleo network serves as a globally trustless and verifiable record of a program execution as well as
|
|
257
268
|
any resulting state changes in private or public data.
|
|
258
269
|
|
|
259
270
|
A simple example of running the "hello world" program on the Aleo network is shown below:
|
|
260
271
|
```typescript
|
|
261
|
-
import { Account, AleoNetworkClient, NetworkRecordProvider, ProgramManager,
|
|
272
|
+
import { Account, AleoNetworkClient, NetworkRecordProvider, ProgramManager, AleoKeyProvider } from '@provablehq/sdk';
|
|
273
|
+
|
|
274
|
+
// Create an account
|
|
275
|
+
const account = new Account();
|
|
276
|
+
|
|
277
|
+
// Create a network client to connect to the Aleo network
|
|
278
|
+
const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1");
|
|
262
279
|
|
|
263
280
|
// Create a key provider that will be used to find public proving & verifying keys for Aleo programs
|
|
264
281
|
const keyProvider = new AleoKeyProvider();
|
|
265
282
|
keyProvider.useCache = true;
|
|
266
283
|
|
|
267
284
|
// Create a record provider that will be used to find records and transaction data for Aleo programs
|
|
268
|
-
const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1");
|
|
269
285
|
const recordProvider = new NetworkRecordProvider(account, networkClient);
|
|
270
286
|
|
|
271
287
|
// Initialize a program manager to talk to the Aleo network with the configured key and record providers
|
|
272
288
|
const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, recordProvider);
|
|
273
289
|
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
290
|
+
// Set the account for the program manager
|
|
291
|
+
programManager.setAccount(account);
|
|
292
|
+
|
|
293
|
+
(async () => {
|
|
294
|
+
try {
|
|
295
|
+
// Provide a key search parameter to find the correct key for the program if they are stored in a memory cache
|
|
296
|
+
const keySearchParams = { cacheKey: "helloworld.aleo:main" };
|
|
297
|
+
console.log("Key search parameters set: ", keySearchParams);
|
|
298
|
+
|
|
299
|
+
// Execute the program using the options provided inline
|
|
300
|
+
const tx_id = await programManager.execute({
|
|
301
|
+
programName: "helloworld.aleo",
|
|
302
|
+
functionName: "main",
|
|
303
|
+
fee: 0.020,
|
|
304
|
+
privateFee: false, // Assuming a value for privateFee
|
|
305
|
+
inputs: ["5u32", "5u32"], // Example inputs matching the function definition
|
|
306
|
+
keySearchParams: keySearchParams,
|
|
307
|
+
privateKey: account.privateKey() // Set the private key
|
|
308
|
+
});
|
|
309
|
+
const transaction = await programManager.networkClient.getTransaction(tx_id);
|
|
310
|
+
console.log("Transaction details: ", transaction);
|
|
311
|
+
} catch (error) {
|
|
312
|
+
console.error("Error executing program:", error);
|
|
313
|
+
}
|
|
314
|
+
})();
|
|
287
315
|
```
|
|
288
316
|
|
|
289
317
|
A reader of the above example may notice the `RecordProvider` and `KeyProvider` classes that were not present in the local
|
|
@@ -294,9 +322,9 @@ These two concepts are explained in more detail below.
|
|
|
294
322
|
|
|
295
323
|
### 2.6 Program proving keys & program records
|
|
296
324
|
|
|
297
|
-
Executing Aleo programs
|
|
325
|
+
Executing Aleo programs using zero-knowledge requires two additional pieces of information:
|
|
298
326
|
|
|
299
|
-
1. **Function Proving & Verifying Keys:** Proving and
|
|
327
|
+
1. **Function Proving & Verifying Keys:** Proving and verifying keys are cryptographic keys that are generated when a
|
|
300
328
|
program function is executed. These keys are public and unique for each function in a program. The proving keys allows any party to
|
|
301
329
|
execute the program and generate a proof that the program was executed correctly. The verifying keys allow any party
|
|
302
330
|
to verify that the proof was generated correctly and the execution is correct. These keys are required to create the
|
|
@@ -332,7 +360,7 @@ to the network (as long as it doesn't already exist) by paying a deployment fee
|
|
|
332
360
|
provides a simple interface for deploying programs to the Aleo network using the program manager.
|
|
333
361
|
|
|
334
362
|
```typescript
|
|
335
|
-
import { Account, AleoNetworkClient, NetworkRecordProvider, ProgramManager,
|
|
363
|
+
import { Account, AleoNetworkClient, NetworkRecordProvider, ProgramManager, AleoKeyProvider} from '@provablehq/sdk';
|
|
336
364
|
|
|
337
365
|
// Create a key provider that will be used to find public proving & verifying keys for Aleo programs
|
|
338
366
|
const keyProvider = new AleoKeyProvider();
|
|
@@ -356,7 +384,7 @@ programManager.setAccount(account)
|
|
|
356
384
|
const program = "program hello_hello.aleo;\n\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n";
|
|
357
385
|
|
|
358
386
|
// Define a fee to pay to deploy the program
|
|
359
|
-
const fee =
|
|
387
|
+
const fee = 3.8; // 3.8 Aleo credits
|
|
360
388
|
|
|
361
389
|
// Deploy the program to the Aleo network
|
|
362
390
|
const tx_id = await programManager.deploy(program, fee);
|
|
@@ -380,300 +408,33 @@ const tx_id = await programManager.deploy(program, fee, undefined, feeRecord);
|
|
|
380
408
|
|
|
381
409
|
### 2.8 React example
|
|
382
410
|
|
|
383
|
-
The above concepts can be tied together in a concrete example of a
|
|
411
|
+
The above concepts can be tied together in a concrete example of a single-page web app. This example can be installed in one
|
|
384
412
|
step by running:
|
|
385
413
|
|
|
386
|
-
`npm create
|
|
387
|
-
|
|
388
|
-
#### Program execution
|
|
389
|
-
|
|
390
|
-
Program execution is a computationally expensive process. For this reason, it is recommended to execute programs in
|
|
391
|
-
Web Workers.
|
|
392
|
-
|
|
393
|
-
<details>
|
|
394
|
-
<summary>Example Web Worker Usage</summary>
|
|
395
|
-
|
|
396
|
-
A worker file that performs the execution can be created as follows:
|
|
397
|
-
`worker.js`
|
|
398
|
-
```jsx
|
|
399
|
-
import * as aleo from "@provablehq/sdk";
|
|
400
|
-
|
|
401
|
-
// Threads are then initialized to execute the program in parallel using multithreading
|
|
402
|
-
await aleo.initThreadPool();
|
|
403
|
-
|
|
404
|
-
/// The program manager is initialized with a key provider and a record provider
|
|
405
|
-
const defaultHost = "https://api.explorer.aleo.org/v1";
|
|
406
|
-
const keyProvider = new aleo.AleoKeyProvider();
|
|
407
|
-
const recordProvider = new aleo.NetworkRecordProvider(new Account(), "https://api.explorer.aleo.org/v1");
|
|
408
|
-
const programManager = new aleo.ProgramManager(
|
|
409
|
-
defaultHost,
|
|
410
|
-
keyProvider,
|
|
411
|
-
recordProvider,
|
|
412
|
-
);
|
|
413
|
-
|
|
414
|
-
// The key provider is set to use an in-memory cache to store keys
|
|
415
|
-
keyProvider.useCache(true);
|
|
416
|
-
|
|
417
|
-
self.postMessage({
|
|
418
|
-
type: "ALEO_WORKER_READY",
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
// The program is executed when specific events are dispatched and then communicates the result to the main thread
|
|
422
|
-
// when execution has finished
|
|
423
|
-
let lastLocalProgram = null;
|
|
424
|
-
self.addEventListener("message", (ev) => {
|
|
425
|
-
if (ev.data.type === "ALEO_EXECUTE_PROGRAM_LOCAL") {
|
|
426
|
-
const {localProgram, aleoFunction, inputs, privateKey} = ev.data;
|
|
427
|
-
|
|
428
|
-
console.log("Web worker: Executing function locally...");
|
|
429
|
-
let startTime = performance.now();
|
|
430
|
-
|
|
431
|
-
(async function () {
|
|
432
|
-
try {
|
|
433
|
-
// Ensure the program is valid and that it contains the function specified
|
|
434
|
-
const program = programManager.createProgramFromSource(localProgram);
|
|
435
|
-
const program_id = program.id();
|
|
436
|
-
if (!program.hasFunction(aleoFunction)) {
|
|
437
|
-
throw `Program ${program_id} does not contain function ${aleoFunction}`;
|
|
438
|
-
}
|
|
439
|
-
const cacheKey = `${program_id}:${aleoFunction}`;
|
|
440
|
-
|
|
441
|
-
// Get the program imports
|
|
442
|
-
const imports =
|
|
443
|
-
programManager.networkClient.getProgramImports(localProgram);
|
|
444
|
-
|
|
445
|
-
// Get the proving and verifying keys for the function
|
|
446
|
-
if (lastLocalProgram !== localProgram) {
|
|
447
|
-
const keys = programManager.executionEngine.synthesizeKeypair(
|
|
448
|
-
localProgram,
|
|
449
|
-
aleoFunction,
|
|
450
|
-
);
|
|
451
|
-
programManager.keyProvider.cacheKeys(cacheKey, [
|
|
452
|
-
keys.provingKey(),
|
|
453
|
-
keys.verifyingKey(),
|
|
454
|
-
]);
|
|
455
|
-
lastLocalProgram = localProgram;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Pass the cache key to the execute function
|
|
459
|
-
const keyParams = new aleo.AleoKeyProviderParams({
|
|
460
|
-
cacheKey: cacheKey,
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
// Execute the function locally
|
|
464
|
-
let response = await programManager.executeOffline(
|
|
465
|
-
localProgram,
|
|
466
|
-
aleoFunction,
|
|
467
|
-
inputs,
|
|
468
|
-
imports,
|
|
469
|
-
keyParams,
|
|
470
|
-
undefined,
|
|
471
|
-
undefined,
|
|
472
|
-
aleo.PrivateKey.from_string(privateKey),
|
|
473
|
-
);
|
|
474
|
-
|
|
475
|
-
// Return the outputs to the main thread
|
|
476
|
-
self.postMessage({
|
|
477
|
-
type: "OFFLINE_EXECUTION_COMPLETED",
|
|
478
|
-
outputs,
|
|
479
|
-
});
|
|
480
|
-
} catch (error) {
|
|
481
|
-
console.error(error);
|
|
482
|
-
self.postMessage({
|
|
483
|
-
type: "ERROR",
|
|
484
|
-
errorMessage: error.toString(),
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
})();
|
|
488
|
-
}
|
|
489
|
-
});
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
The Web Worker can then be initialized in a worker provider component which uses React effects
|
|
493
|
-
|
|
494
|
-
```jsx
|
|
495
|
-
import { useEffect, useState } from "react";
|
|
496
|
-
import WorkerContext from "./WorkerContext";
|
|
497
|
-
|
|
498
|
-
const WorkerProvider = ({ children }) => {
|
|
499
|
-
const [worker, setWorker] = useState(null);
|
|
500
|
-
const [workerReady, setWorkerReady] = useState(false);
|
|
414
|
+
`npm create leo-app@latest`
|
|
501
415
|
|
|
502
|
-
|
|
503
|
-
let worker = new Worker(new URL("./worker.js", import.meta.url), {
|
|
504
|
-
type: "module",
|
|
505
|
-
});
|
|
506
|
-
setWorker(worker);
|
|
507
|
-
|
|
508
|
-
worker.onmessage = (event) => {
|
|
509
|
-
if (event.data.type === "ALEO_WORKER_READY") {
|
|
510
|
-
setWorkerReady(true);
|
|
511
|
-
}
|
|
512
|
-
};
|
|
513
|
-
|
|
514
|
-
return () => {
|
|
515
|
-
worker.terminate();
|
|
516
|
-
};
|
|
517
|
-
}, []);
|
|
518
|
-
|
|
519
|
-
if (!workerReady) {
|
|
520
|
-
return (
|
|
521
|
-
<>
|
|
522
|
-
<div className="spinner">
|
|
523
|
-
<div className="dot1"></div>
|
|
524
|
-
</div>
|
|
525
|
-
</>
|
|
526
|
-
);
|
|
527
|
-
}
|
|
416
|
+
You will then be prompted to select either Vanilla, React, or Node.js as the template for the project. For this example, select Vanilla.
|
|
528
417
|
|
|
529
|
-
|
|
530
|
-
<WorkerContext.Provider value={worker}>
|
|
531
|
-
{children}
|
|
532
|
-
</WorkerContext.Provider>
|
|
533
|
-
);
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
export default WorkerProvider;
|
|
537
|
-
```
|
|
538
|
-
|
|
539
|
-
</details>
|
|
540
|
-
|
|
541
|
-
Using both Web Workers and a Wasm initialization in a React hook, a single-page app can be created that executes
|
|
542
|
-
Aleo zero-knowledge programs.
|
|
543
|
-
|
|
544
|
-
<details>
|
|
545
|
-
<summary>Example App.jsx Implementing Zero-Knowledge Program Execution</summary>
|
|
546
|
-
|
|
547
|
-
```jsx
|
|
548
|
-
import { useEffect, useState } from "react";
|
|
549
|
-
import reactLogo from "./assets/react.svg";
|
|
550
|
-
import aleoLogo from "./assets/aleo.png";
|
|
551
|
-
import "./App.css";
|
|
552
|
-
import { useAleoWASM } from "./aleo-wasm-hook";
|
|
553
|
-
|
|
554
|
-
function App() {
|
|
555
|
-
const [count, setCount] = useState(0);
|
|
556
|
-
const aleo = useAleoWASM();
|
|
557
|
-
const [account, setAccount] = useState(null);
|
|
558
|
-
const [loading, setLoading] = useState(false);
|
|
559
|
-
|
|
560
|
-
const generateAccount = () => {
|
|
561
|
-
setAccount(new aleo.PrivateKey());
|
|
562
|
-
};
|
|
563
|
-
|
|
564
|
-
const [worker, setWorker] = useState(null);
|
|
565
|
-
|
|
566
|
-
useEffect(() => {
|
|
567
|
-
if (worker === null) {
|
|
568
|
-
const spawnedWorker = spawnWorker();
|
|
569
|
-
setWorker(spawnedWorker);
|
|
570
|
-
return () => {
|
|
571
|
-
spawnedWorker.terminate();
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
}, []);
|
|
575
|
-
|
|
576
|
-
function spawnWorker() {
|
|
577
|
-
return new Worker(new URL("workers/worker.js", import.meta.url), {
|
|
578
|
-
type: "module",
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
function postMessagePromise(worker, message) {
|
|
583
|
-
return new Promise((resolve, reject) => {
|
|
584
|
-
worker.onmessage = (event) => {
|
|
585
|
-
resolve(event.data);
|
|
586
|
-
};
|
|
587
|
-
worker.onerror = (error) => {
|
|
588
|
-
reject(error);
|
|
589
|
-
};
|
|
590
|
-
worker.postMessage(message);
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
async function execute() {
|
|
595
|
-
const hello_hello_program =
|
|
596
|
-
"program hello_hello.aleo;\n" +
|
|
597
|
-
"\n" +
|
|
598
|
-
"function hello:\n" +
|
|
599
|
-
" input r0 as u32.public;\n" +
|
|
600
|
-
" input r1 as u32.private;\n" +
|
|
601
|
-
" add r0 r1 into r2;\n" +
|
|
602
|
-
" output r2 as u32.private;\n";
|
|
603
|
-
|
|
604
|
-
setLoading(true);
|
|
605
|
-
const result = await postMessagePromise(worker, {
|
|
606
|
-
type: "ALEO_EXECUTE_PROGRAM_LOCAL",
|
|
607
|
-
localProgram: hello_hello_program,
|
|
608
|
-
aleoFunction: "hello",
|
|
609
|
-
inputs: ["5u32", "5u32"],
|
|
610
|
-
privateKey: account.to_string(),
|
|
611
|
-
});
|
|
612
|
-
setLoading(false);
|
|
613
|
-
|
|
614
|
-
alert(JSON.stringify(result));
|
|
615
|
-
}
|
|
418
|
+
#### Program execution
|
|
616
419
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
<div>
|
|
620
|
-
<a href="https://aleo.org" target="_blank">
|
|
621
|
-
<img src={aleoLogo} className="logo" alt="Aleo logo" />
|
|
622
|
-
</a>
|
|
623
|
-
<a href="https://react.dev" target="_blank">
|
|
624
|
-
<img src={reactLogo} className="logo react" alt="React logo" />
|
|
625
|
-
</a>
|
|
626
|
-
</div>
|
|
627
|
-
<h1>Aleo + React</h1>
|
|
628
|
-
<div className="card">
|
|
629
|
-
<button onClick={() => setCount((count) => count + 1)}>
|
|
630
|
-
count is {count}
|
|
631
|
-
</button>
|
|
632
|
-
<p>
|
|
633
|
-
<button onClick={generateAccount}>
|
|
634
|
-
{account
|
|
635
|
-
? `Account is ${JSON.stringify(account.to_string())}`
|
|
636
|
-
: `Click to generate account`}
|
|
637
|
-
</button>
|
|
638
|
-
</p>
|
|
639
|
-
<p>
|
|
640
|
-
<button disabled={!account || loading} onClick={execute}>
|
|
641
|
-
{loading
|
|
642
|
-
? `Executing...check console for details...`
|
|
643
|
-
: `Execute hello_hello.aleo`}
|
|
644
|
-
</button>
|
|
645
|
-
</p>
|
|
646
|
-
<p>
|
|
647
|
-
Edit <code>src/App.jsx</code> and save to test HMR
|
|
648
|
-
</p>
|
|
649
|
-
</div>
|
|
650
|
-
<p className="read-the-docs">
|
|
651
|
-
Click on the Aleo and React logos to learn more
|
|
652
|
-
</p>
|
|
653
|
-
</>
|
|
654
|
-
);
|
|
655
|
-
}
|
|
420
|
+
Program execution is a computationally-expensive process. For this reason, it is recommended to execute programs in
|
|
421
|
+
web workers. Create-Leo-App will automatically create a web worker for you that performs the execution called `worker.js`.
|
|
656
422
|
|
|
657
|
-
export default App;
|
|
658
|
-
```
|
|
659
|
-
</details>
|
|
660
423
|
|
|
661
|
-
|
|
662
|
-
A full example of this implementation can be found [here](https://github.com/ProvableHQ/sdk/blob/testnet3/create-aleo-app/template-react-managed-worker/src/App.jsx)
|
|
424
|
+
A full example of this implementation can be found [here](https://github.com/ProvableHQ/sdk/tree/testnet3/create-leo-app/template-vanilla)
|
|
663
425
|
|
|
664
426
|
## 3. Aleo Credit Transfers
|
|
665
427
|
|
|
666
428
|
### 3.1 Aleo credits
|
|
667
429
|
|
|
668
|
-
|
|
669
|
-
execution on the Aleo network.
|
|
430
|
+
Aleo Credits are used to access blockspace and computational resources on the network, with users paying Credits to submit transactions and have them processed.
|
|
670
431
|
|
|
671
432
|
Aleo credits are defined in the [credits.aleo](https://explorer.aleo.org/program/credits.aleo) program. This program is
|
|
672
433
|
deployed to the Aleo network and defines data structures representing Aleo credits and the functions used to manage them.
|
|
673
434
|
|
|
674
|
-
There are two ways to hold Aleo credits
|
|
435
|
+
There are two ways to hold Aleo credits:
|
|
675
436
|
|
|
676
|
-
#### 1 - Private balances via
|
|
437
|
+
#### 1 - Private balances via `credits.aleo` records
|
|
677
438
|
The first method is owning a `credits` record which enables a participant in the Aleo
|
|
678
439
|
network to hold a private balance of Aleo credits.
|
|
679
440
|
```
|
|
@@ -685,8 +446,8 @@ record credits:
|
|
|
685
446
|
A user's total private credits balance will consist of all unspent `credits` records owned by the user with a non-zero
|
|
686
447
|
`microcredits` value.
|
|
687
448
|
|
|
688
|
-
#### 2 - Public balances via credits.aleo account
|
|
689
|
-
The second is by holding a `balance` in the `account` mapping in the `credits.aleo` program on the Aleo network.
|
|
449
|
+
#### 2 - Public balances via `credits.aleo` account mappings
|
|
450
|
+
The second method is by holding a `balance` in the `account` mapping in the `credits.aleo` program on the Aleo network.
|
|
690
451
|
|
|
691
452
|
```
|
|
692
453
|
mapping account:
|
|
@@ -705,7 +466,7 @@ program under the hood.
|
|
|
705
466
|
|
|
706
467
|
There are four transfer functions available.
|
|
707
468
|
|
|
708
|
-
#### 1. transfer_private
|
|
469
|
+
#### 1. `transfer_private`
|
|
709
470
|
|
|
710
471
|
Takes a `credits` record owned by the sender, subtracts an amount from it, and adds that amount
|
|
711
472
|
to a new record owned by the receiver. This function is 100% private and does not affect the `account` mapping.
|
|
@@ -719,7 +480,8 @@ graph LR
|
|
|
719
480
|
|
|
720
481
|
```
|
|
721
482
|
|
|
722
|
-
#### 2. transfer_private_to_public
|
|
483
|
+
#### 2. `transfer_private_to_public`
|
|
484
|
+
|
|
723
485
|
Takes a `credits` record owned by the sender, subtracts an amount from it, and adds
|
|
724
486
|
that amount to the `account` mapping of the receiver. This function is 50% private and 50% public. It consumes a record
|
|
725
487
|
as a private input and generates a public balance in the `account` mapping entry belonging to the receiver.
|
|
@@ -734,7 +496,7 @@ graph LR
|
|
|
734
496
|
t1--amount 3000u64-->m1
|
|
735
497
|
```
|
|
736
498
|
|
|
737
|
-
#### 3. transfer_public
|
|
499
|
+
#### 3. `transfer_public`
|
|
738
500
|
|
|
739
501
|
Subtracts an amount of `credits` stored in the `account` mapping of the `credits.aleo` program, and
|
|
740
502
|
adds that amount to the `account` mapping of the receiver. This function is 100% public and does not consume or generate
|
|
@@ -753,7 +515,8 @@ graph LR
|
|
|
753
515
|
end
|
|
754
516
|
```
|
|
755
517
|
|
|
756
|
-
#### 4. transfer_public_to_private
|
|
518
|
+
#### 4. `transfer_public_to_private`
|
|
519
|
+
|
|
757
520
|
Subtracts an amount `credits` stored in the `account` mapping of the `credits.aleo program`
|
|
758
521
|
and adds that amount to a new private record owned by the receiver. This function is 50% private and 50% public.
|
|
759
522
|
It publicly consumes a balance in the `account` mapping entry belonging to the sender and generates a private record
|
|
@@ -777,7 +540,7 @@ All four of these functions can be used to transfer credits between users via th
|
|
|
777
540
|
`ProgramManager` by specifying the transfer type as the third argument.
|
|
778
541
|
|
|
779
542
|
```typescript
|
|
780
|
-
import { Account, ProgramManager, AleoKeyProvider, NetworkRecordProvider, AleoNetworkClient } from '@
|
|
543
|
+
import { Account, ProgramManager, AleoKeyProvider, NetworkRecordProvider, AleoNetworkClient } from '@provablehq/sdk';
|
|
781
544
|
|
|
782
545
|
// Create a new NetworkClient, KeyProvider, and RecordProvider
|
|
783
546
|
const account = Account.from_string({privateKey: "user1PrivateKey"});
|
|
@@ -830,7 +593,7 @@ const public_balance = networkClient.getMappingValue("credits.aleo", USER_1_ADDR
|
|
|
830
593
|
## 4. Managing Program Data and Private State
|
|
831
594
|
|
|
832
595
|
### 4.1 Private state data: records
|
|
833
|
-
Records are analogous to concept of [UTXOs](https://en.wikipedia.org/wiki/Unspent_transaction_output). When a record is
|
|
596
|
+
Records are analogous to the concept of [UTXOs](https://en.wikipedia.org/wiki/Unspent_transaction_output). When a record is
|
|
834
597
|
created by a program, it can then be consumed later by the same program as an input to a function. Once a record is used
|
|
835
598
|
as an input, it is considered consumed and cannot be used again. In many cases a new record will be created from the output
|
|
836
599
|
of the function. Records are private by default and are associated with a single Aleo program and a single private key
|
|
@@ -841,7 +604,7 @@ representing a user.
|
|
|
841
604
|
A straightforward example of a usage of records in a program can be demonstrated by explaining the process of private
|
|
842
605
|
value transfers of Aleo credits on the Aleo network.
|
|
843
606
|
|
|
844
|
-
Aleo credits are
|
|
607
|
+
Aleo credits are used for all on-chain execution and deployment fees. Credits can be public
|
|
845
608
|
or private. Private credits are represented by the `credits` record in the [credits.aleo](https://www.aleo.network/programs/credits.aleo)
|
|
846
609
|
program.
|
|
847
610
|
|
|
@@ -871,10 +634,10 @@ function transfer_private:
|
|
|
871
634
|
output r5 as credits.record;
|
|
872
635
|
```
|
|
873
636
|
|
|
874
|
-
The `transfer_private` function can be graphically represented by the graph below. In the graph the first record
|
|
637
|
+
The `transfer_private` function can be graphically represented by the graph below. In the graph the first record, Record 1,
|
|
875
638
|
is consumed and can never be used again. From the data in Record 1, two more records are created. One containing
|
|
876
639
|
the intended amount for the recipient which is now owned by the recipient and another containing the remaining credits
|
|
877
|
-
which
|
|
640
|
+
which are sent back to the sender.
|
|
878
641
|
|
|
879
642
|
```mermaid
|
|
880
643
|
graph LR
|
|
@@ -907,7 +670,7 @@ The above state chain would be executed in the following way using the SDK:
|
|
|
907
670
|
#### Step 1 - User 1 sends a private value transfer to User 2
|
|
908
671
|
```typescript
|
|
909
672
|
// USER 1
|
|
910
|
-
import { Account, ProgramManager, AleoKeyProvider, NetworkRecordProvider, AleoNetworkClient } from '@
|
|
673
|
+
import { Account, ProgramManager, AleoKeyProvider, NetworkRecordProvider, AleoNetworkClient } from '@provablehq/sdk';
|
|
911
674
|
|
|
912
675
|
// Create a new NetworkClient, KeyProvider, and RecordProvider
|
|
913
676
|
const account = Account.from_string({privateKey: "user1PrivateKey"});
|
|
@@ -920,15 +683,15 @@ const USER_2_ADDRESS = "user2Address";
|
|
|
920
683
|
const programManager = new ProgramManager("https://api.explorer.aleo.org/v1", keyProvider, recordProvider);
|
|
921
684
|
programManager.setAccount(account);
|
|
922
685
|
|
|
923
|
-
/// Send private transfer to
|
|
686
|
+
/// Send private transfer to User 2
|
|
924
687
|
const tx_id = await programManager.transfer(1, USER_2_ADDRESS, "transfer_private", 0.2);
|
|
925
688
|
```
|
|
926
689
|
|
|
927
|
-
#### Step 2 - User 2 receives the transaction ID and fetches the credits record they received from
|
|
690
|
+
#### Step 2 - User 2 receives the transaction ID and fetches the credits record they received from User 1 from the network. They then send it to User 3
|
|
928
691
|
|
|
929
692
|
```typescript
|
|
930
693
|
// USER 2
|
|
931
|
-
import { Account, ProgramManager, AleoKeyProvider, NetworkRecordProvider, AleoNetworkClient } from '@
|
|
694
|
+
import { Account, ProgramManager, AleoKeyProvider, NetworkRecordProvider, AleoNetworkClient } from '@provablehq/sdk';
|
|
932
695
|
|
|
933
696
|
// Create a new NetworkClient, KeyProvider, and RecordProvider
|
|
934
697
|
const account = Account.from_string({privateKey: "user2PrivateKey"});
|
|
@@ -953,18 +716,18 @@ const USER_3_ADDRESS = "user3Address";
|
|
|
953
716
|
const tx_id = await programManager.transfer(1, USER_3_ADDRESS, "transfer_private", 0.2, undefined, recordPlaintext);
|
|
954
717
|
```
|
|
955
718
|
|
|
956
|
-
When an execution such as transfer_private consumes or generates a record, an encrypted transcript of the execution
|
|
719
|
+
When an execution such as `transfer_private` consumes or generates a record, an encrypted transcript of the execution containing an encrypted version of the record output and a transaction ID is posted on the network.
|
|
957
720
|
|
|
958
721
|
Because the records are encrypted when they're posted on the network, they do not reveal any information about the party
|
|
959
722
|
who executed the program, nor the contents of the record. The only information that is revealed is the program ID,
|
|
960
723
|
function name, encrypted function inputs, and the transaction ID of the program execution. No user except for the recipient
|
|
961
724
|
of the record can see the contents of the record.
|
|
962
725
|
|
|
963
|
-
Below, you can see
|
|
726
|
+
Below, you can see the exact data which is posted to the Aleo network when `transfer_private` is run. Note that the
|
|
964
727
|
record, the amount transferred, and both the sender and recipient addresses are all encrypted.
|
|
965
728
|
|
|
966
729
|
<details>
|
|
967
|
-
<summary
|
|
730
|
+
<summary>`transfer_private` Execution Transcript</summary>
|
|
968
731
|
|
|
969
732
|
```json
|
|
970
733
|
"transactions": [
|
|
@@ -1029,7 +792,7 @@ that are not owned by the user will fail.
|
|
|
1029
792
|
Record decryption and ownership verification can be done in the SDK using the following code:
|
|
1030
793
|
|
|
1031
794
|
```typescript
|
|
1032
|
-
import { Account, RecordCiphertext, RecordPlaintext } from '@
|
|
795
|
+
import { Account, RecordCiphertext, RecordPlaintext } from '@provablehq/sdk';
|
|
1033
796
|
|
|
1034
797
|
// Create an account from an existing private key
|
|
1035
798
|
const account = Account.from_string({privateKey: "existingPrivateKey"});
|
|
@@ -1053,7 +816,7 @@ if (RecordCiphertext.is_owner(account.viewKey())) {
|
|
|
1053
816
|
Mappings are simple key value stores defined in a program. They are represented by a key and a value each of a specified
|
|
1054
817
|
type. They are stored directly within the Aleo blockchain and can be publicly read by any participant in the Aleo network.
|
|
1055
818
|
|
|
1056
|
-
An example of a mapping usage is `account` mapping in the `credits.aleo` program.
|
|
819
|
+
An example of a mapping usage is the `account` mapping in the `credits.aleo` program.
|
|
1057
820
|
```
|
|
1058
821
|
mapping account:
|
|
1059
822
|
key owner as address.public;
|
|
@@ -1098,7 +861,7 @@ class provides the `getMapping` method to read the public mappings within an pro
|
|
|
1098
861
|
read the value of a specific key within a mapping.
|
|
1099
862
|
|
|
1100
863
|
```typescript
|
|
1101
|
-
import {
|
|
864
|
+
import { AleoNetworkClient } from '@provablehq/sdk';
|
|
1102
865
|
|
|
1103
866
|
const networkClient = new AleoNetworkClient("https://api.explorer.aleo.org/v1");
|
|
1104
867
|
const creditsMappings = networkClient.getMappings("credits.aleo");
|
|
@@ -1110,7 +873,7 @@ assert(publicCredits === "0u64");
|
|
|
1110
873
|
|
|
1111
874
|
### 4.5 Initializing & updating mappings
|
|
1112
875
|
Updating mappings is done by executing a program function on the Aleo network which has a finalize block that updates the
|
|
1113
|
-
program's mapping. For instance the `transfer_public` function in the `credits.aleo` program updates the `account`
|
|
876
|
+
program's mapping. For instance, the `transfer_public` function in the `credits.aleo` program updates the `account`
|
|
1114
877
|
mapping (and thus a user's balance) when called.
|
|
1115
878
|
|
|
1116
879
|
```
|
|
@@ -1143,7 +906,7 @@ consumed. Therefore, it is important to ensure that the inputs to a function are
|
|
|
1143
906
|
A simple example of a mapping update can be shown by simply executing 'transfer_public` as shown below.
|
|
1144
907
|
|
|
1145
908
|
```typescript
|
|
1146
|
-
import { Account, ProgramManager, AleoKeyProvider, NetworkRecordProvider, AleoNetworkClient } from '@
|
|
909
|
+
import { Account, ProgramManager, AleoKeyProvider, NetworkRecordProvider, AleoNetworkClient } from '@provablehq/sdk';
|
|
1147
910
|
|
|
1148
911
|
// Create a new NetworkClient, KeyProvider, and RecordProvider
|
|
1149
912
|
const account = Account.from_string({privateKey: "user1PrivateKey"});
|
|
@@ -1171,7 +934,7 @@ A full list of methods provided by the `AleoNetworkClient` class and usage examp
|
|
|
1171
934
|
|
|
1172
935
|
## Further Documentation
|
|
1173
936
|
|
|
1174
|
-
API documentation for this package, the Leo Language, and Aleo instructions can be found
|
|
937
|
+
API documentation for this package, the Leo Language, and Aleo instructions can be found in the [Leo Developer Docs](https://docs.leo-lang.org/getting_started).
|
|
1175
938
|
|
|
1176
939
|
To view the API documentation for this package locally, open `docs/index.html`.
|
|
1177
940
|
To regenerate the documentation, run `npx jsdoc --configure jsdoc.json --verbose`
|