create-leo-app 0.8.2 → 0.8.6
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/package.json +1 -1
- package/template-extension/src/service_worker.js +1 -1
- package/template-offline-public-transaction-ts/README.md +13 -17
- package/template-offline-public-transaction-ts/src/helpers.ts +1 -1
- package/template-offline-public-transaction-ts/src/index.ts +59 -39
- package/template-react-leo/src/App.jsx +1 -1
- package/template-react-ts/src/App.tsx +1 -1
- package/template-react-ts/src/components/Sidebar.jsx +47 -0
- package/template-react-ts/src/pages/AuctioneerPage.jsx +144 -0
- package/template-react-ts/src/pages/BidderPage.jsx +142 -0
- package/template-vanilla/main.js +1 -1
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@ async function createOffscreen(path) {
|
|
|
13
13
|
await chrome.offscreen.createDocument({
|
|
14
14
|
url: offscreenUrl,
|
|
15
15
|
reasons: ["WORKERS"],
|
|
16
|
-
justification: "Top-level await and Workers cannot be used in service workers, but they are necessary to use the
|
|
16
|
+
justification: "Top-level await and Workers cannot be used in service workers, but they are necessary to use the Provable SDK.",
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Offline Transaction Builder
|
|
2
2
|
|
|
3
3
|
## 1. Overview
|
|
4
|
-
### 1.1 Proving Keys for Zero
|
|
5
|
-
To achieve zero
|
|
6
|
-
zero
|
|
4
|
+
### 1.1 Proving Keys for Zero-Knowledge Function Execution
|
|
5
|
+
To achieve zero-knowledge execution, all Aleo functions require a `ProvingKey` and `VerifyingKey` in order to build a
|
|
6
|
+
zero-knowledge zk-SNARK proof of execution. If a user does not possess these keys for a function, they are normally
|
|
7
7
|
downloaded from the internet when the function is called.
|
|
8
8
|
|
|
9
9
|
### 1.2 Key Providers
|
|
@@ -21,31 +21,27 @@ the internet for it. This provides a way to build Aleo execution transactions wi
|
|
|
21
21
|
This pathway is suitable for use-cases such as hardware wallets or air-gapped machines used
|
|
22
22
|
for building secure transactions.
|
|
23
23
|
|
|
24
|
-
### 1.4
|
|
24
|
+
### 1.4 Transaction Types
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
Several types of transactions can be built and executed using this template:
|
|
27
|
+
|
|
28
|
+
`bond_public`
|
|
29
|
+
`unbond_public`
|
|
30
|
+
`claim_unbond_public`
|
|
28
31
|
|
|
29
32
|
## 2. Usage
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
First run this command online to download the key material to disk:
|
|
34
|
+
`npm run build`
|
|
33
35
|
|
|
34
|
-
`npm
|
|
36
|
+
`npm run dev`
|
|
35
37
|
|
|
36
38
|
Once this command is run, all proving keys for the `transfer_public`, `bond_public`, `unbond_public`, and
|
|
37
|
-
`claim_unbond_public` functions will be downloaded to the
|
|
39
|
+
`claim_unbond_public` functions will be downloaded to the `dist/keys` folder. The machine can then be disconnected from
|
|
38
40
|
the internet and the `OfflineKeyProvider` will search this directory for the function proving keys when building the
|
|
39
41
|
transaction instead of connecting to the internet. Alternatively you can skip the online step entirely by adding the proving key creating this directory manually and
|
|
40
42
|
adding the key material yourself.
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Once the key material is downloaded, turn off your internet connection and run the following command:
|
|
45
|
-
|
|
46
|
-
`npm start`
|
|
47
|
-
|
|
48
|
-
You should see the transactions being built and the resulting transaction IDs printed to the console.
|
|
44
|
+
Once the keys are downloaded to your local machine, the offline transactions will be built without requiring an internet connection.
|
|
49
45
|
|
|
50
46
|
## 3. Notes
|
|
51
47
|
|
|
@@ -28,7 +28,7 @@ async function preDownloadTransferKeys() {
|
|
|
28
28
|
const keysDirPath = path.join(__dirname, "keys");
|
|
29
29
|
await fsPromises.mkdir(keysDirPath, { recursive: true });
|
|
30
30
|
|
|
31
|
-
for (const keyData of [CREDITS_PROGRAM_KEYS.transfer_public, CREDITS_PROGRAM_KEYS.fee_public]) {
|
|
31
|
+
for (const keyData of [CREDITS_PROGRAM_KEYS.transfer_public, CREDITS_PROGRAM_KEYS.fee_public, CREDITS_PROGRAM_KEYS.transfer_public_as_signer]) {
|
|
32
32
|
try {
|
|
33
33
|
keyPaths[keyData.locator] = await downloadAndSaveKey(keyData, keysDirPath);
|
|
34
34
|
} catch (error) {
|
|
@@ -15,10 +15,11 @@ async function buildTransferPublicTxOffline(recipientAddress: Address, amount: n
|
|
|
15
15
|
// Create the proving keys from the key bytes on the offline machine
|
|
16
16
|
console.log("Creating proving keys from local key files");
|
|
17
17
|
const feePublicKeyBytes = await getLocalKey(<string>keyPaths[CREDITS_PROGRAM_KEYS.fee_public.locator]);
|
|
18
|
-
const transferPublicAsSignerKeyBytes = await getLocalKey(<string>keyPaths[CREDITS_PROGRAM_KEYS.transfer_public_as_signer.locator]);
|
|
19
18
|
const feePublicProvingKey = ProvingKey.fromBytes(feePublicKeyBytes);
|
|
20
|
-
const transferPublicProvingKey = ProvingKey.fromBytes(
|
|
21
|
-
|
|
19
|
+
const transferPublicProvingKey = ProvingKey.fromBytes(
|
|
20
|
+
await getLocalKey(<string>keyPaths[CREDITS_PROGRAM_KEYS.transfer_public.locator])
|
|
21
|
+
);
|
|
22
|
+
|
|
22
23
|
// Create an offline key provider
|
|
23
24
|
console.log("Creating offline key provider");
|
|
24
25
|
const offlineKeyProvider = new OfflineKeyProvider();
|
|
@@ -27,10 +28,25 @@ async function buildTransferPublicTxOffline(recipientAddress: Address, amount: n
|
|
|
27
28
|
// keys into the key manager.
|
|
28
29
|
console.log("Inserting proving keys into key provider");
|
|
29
30
|
offlineKeyProvider.insertFeePublicKeys(feePublicProvingKey);
|
|
31
|
+
|
|
32
|
+
try {
|
|
30
33
|
offlineKeyProvider.insertTransferPublicKeys(transferPublicProvingKey);
|
|
34
|
+
console.log("Successfully inserted proving key");
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error("Failed to insert proving key:", err);
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
|
|
32
40
|
// Create an offline query to complete the inclusion proof
|
|
33
|
-
|
|
41
|
+
let offlineQuery: OfflineQuery;
|
|
42
|
+
const blockHeight = 0;
|
|
43
|
+
// TODO this is a placeholder block height for now, which offlineQuery now requires
|
|
44
|
+
try {
|
|
45
|
+
const offlineQuery = new OfflineQuery(blockHeight, latestStateRoot);
|
|
46
|
+
console.log("Successfully created OfflineQuery", offlineQuery);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.error("Failed to create OfflineQuery:", err);
|
|
49
|
+
}
|
|
34
50
|
|
|
35
51
|
// Insert the key provider into the program manager
|
|
36
52
|
programManager.setKeyProvider(offlineKeyProvider);
|
|
@@ -47,7 +63,13 @@ async function buildTransferPublicTxOffline(recipientAddress: Address, amount: n
|
|
|
47
63
|
}
|
|
48
64
|
|
|
49
65
|
/// Build bonding and unbonding transactions without connection to the internet
|
|
50
|
-
async function buildBondingTxOffline(
|
|
66
|
+
async function buildBondingTxOffline(
|
|
67
|
+
validatorAddress: Address,
|
|
68
|
+
withdrawalAddress: Address,
|
|
69
|
+
amount: number,
|
|
70
|
+
latestStateRoot: string,
|
|
71
|
+
keyPaths: {}
|
|
72
|
+
): Promise<Transaction[]> {
|
|
51
73
|
// Create an offline program manager
|
|
52
74
|
const programManager = new ProgramManager();
|
|
53
75
|
|
|
@@ -70,8 +92,7 @@ async function buildBondingTxOffline(stakerAddress: Address, validatorAddress:
|
|
|
70
92
|
console.log("Creating offline key provider");
|
|
71
93
|
const offlineKeyProvider = new OfflineKeyProvider();
|
|
72
94
|
|
|
73
|
-
// Insert the proving keys into the offline key provider
|
|
74
|
-
// keys into the key manager.
|
|
95
|
+
// Insert the proving keys into the offline key provider
|
|
75
96
|
console.log("Inserting proving keys into key provider");
|
|
76
97
|
offlineKeyProvider.insertFeePublicKeys(feePublicProvingKey);
|
|
77
98
|
offlineKeyProvider.insertBondPublicKeys(bondPublicProvingKey);
|
|
@@ -83,49 +104,48 @@ async function buildBondingTxOffline(stakerAddress: Address, validatorAddress:
|
|
|
83
104
|
|
|
84
105
|
// Build the bonding transactions offline
|
|
85
106
|
console.log("Building a bond_public execution transaction offline");
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
},
|
|
90
|
-
offlineParams: {
|
|
91
|
-
offlineQuery: new OfflineQuery(latestStateRoot)
|
|
92
|
-
}
|
|
107
|
+
|
|
108
|
+
if (!latestStateRoot) {
|
|
109
|
+
throw new Error("latestStateRoot is undefined");
|
|
93
110
|
}
|
|
94
111
|
|
|
112
|
+
const bondPublicOptions = {
|
|
113
|
+
keySearchParams: OfflineSearchParams.bondPublicKeyParams(),
|
|
114
|
+
offlineQuery: new OfflineQuery(0, latestStateRoot)
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
|
|
95
118
|
const bondTx = <Transaction>await programManager.buildBondPublicTransaction(
|
|
96
|
-
stakerAddress.to_string(),
|
|
97
119
|
validatorAddress.to_string(),
|
|
98
120
|
withdrawalAddress.to_string(),
|
|
99
121
|
amount,
|
|
100
|
-
bondPublicOptions
|
|
101
|
-
)
|
|
122
|
+
bondPublicOptions
|
|
123
|
+
);
|
|
124
|
+
|
|
102
125
|
console.log("\nbond_public transaction built!\n");
|
|
103
126
|
|
|
104
|
-
console.log("Building an unbond_public execution transaction offline")
|
|
105
127
|
const unbondPublicOptions = {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
offlineParams: {
|
|
110
|
-
offlineQuery: new OfflineQuery(latestStateRoot)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
128
|
+
keySearchParams: OfflineSearchParams.unbondPublicKeyParams(),
|
|
129
|
+
offlineQuery: new OfflineQuery(0, latestStateRoot)
|
|
130
|
+
};
|
|
113
131
|
|
|
114
|
-
const unBondTx = <Transaction>await programManager.buildUnbondPublicTransaction(
|
|
132
|
+
const unBondTx = <Transaction>await programManager.buildUnbondPublicTransaction(
|
|
133
|
+
stakerAddress.to_string(),
|
|
134
|
+
amount,
|
|
135
|
+
unbondPublicOptions
|
|
136
|
+
);
|
|
115
137
|
console.log("\nunbond_public transaction built!\n");
|
|
116
138
|
|
|
117
|
-
console.log("Building a claim_unbond_public transaction offline")
|
|
118
|
-
// Build the claim unbonding transaction offline
|
|
139
|
+
console.log("Building a claim_unbond_public transaction offline");
|
|
119
140
|
const claimUnbondPublicOptions = {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
offlineParams: {
|
|
124
|
-
offlineQuery: new OfflineQuery(latestStateRoot)
|
|
125
|
-
}
|
|
126
|
-
}
|
|
141
|
+
keySearchParams: OfflineSearchParams.claimUnbondPublicKeyParams(),
|
|
142
|
+
offlineQuery: new OfflineQuery(0, latestStateRoot)
|
|
143
|
+
};
|
|
127
144
|
|
|
128
|
-
const claimUnbondTx = <Transaction>await programManager.buildClaimUnbondPublicTransaction(
|
|
145
|
+
const claimUnbondTx = <Transaction>await programManager.buildClaimUnbondPublicTransaction(
|
|
146
|
+
stakerAddress.to_string(),
|
|
147
|
+
claimUnbondPublicOptions
|
|
148
|
+
);
|
|
129
149
|
console.log("\nclaim_unbond_public transaction built!\n");
|
|
130
150
|
return [bondTx, unBondTx, claimUnbondTx];
|
|
131
151
|
}
|
|
@@ -153,13 +173,13 @@ console.log(`\n---------------transfer_public transaction---------------\n${tran
|
|
|
153
173
|
console.log(`---------------------------------------------------------`);
|
|
154
174
|
|
|
155
175
|
// Build bonding & unbonding transactions
|
|
156
|
-
const bondTransactions = await buildBondingTxOffline(
|
|
176
|
+
const bondTransactions = await buildBondingTxOffline(validatorAddress, withdrawalAddress, 100, latestStateRoot, bondingKeyPaths);
|
|
157
177
|
console.log("Bonding transactions built offline!");
|
|
158
178
|
console.log(`\n-----------------bond_public transaction-----------------\n${bondTransactions[0]}`);
|
|
159
179
|
console.log(`---------------------------------------------------------`);
|
|
160
180
|
console.log(`\n----------------unbond_public transaction:---------------\n${bondTransactions[1]}`);
|
|
161
181
|
console.log(`---------------------------------------------------------`);
|
|
162
|
-
console.log(`\n-----------------
|
|
182
|
+
console.log(`\n-----------------claim_unbond_public transaction:---------------\n${bondTransactions[2]}`);
|
|
163
183
|
console.log(`---------------------------------------------------------`);
|
|
164
184
|
//---------------------------------------------------------
|
|
165
185
|
|
|
@@ -168,4 +188,4 @@ console.log(`---------------------------------------------------------`);
|
|
|
168
188
|
// ONLINE COMPONENT (Uncomment this part to send the transaction to the Aleo Network on an internet connected machine)
|
|
169
189
|
// Submit the transaction to the network
|
|
170
190
|
// const transferTxId = await networkClient.submitTransaction(transferTx);
|
|
171
|
-
//---------------------------------------------------------
|
|
191
|
+
//---------------------------------------------------------
|
|
@@ -34,7 +34,7 @@ function App() {
|
|
|
34
34
|
try {
|
|
35
35
|
const result = await aleoWorker.deployProgram(helloworld_program);
|
|
36
36
|
console.log("Transaction:")
|
|
37
|
-
console.log("https://explorer.
|
|
37
|
+
console.log("https://explorer.provable.com/transaction/" + result)
|
|
38
38
|
alert("Transaction ID: " + result);
|
|
39
39
|
} catch (e) {
|
|
40
40
|
console.log(e)
|
|
@@ -34,7 +34,7 @@ function App() {
|
|
|
34
34
|
try {
|
|
35
35
|
const result = await aleoWorker.deployProgram(helloworld_program);
|
|
36
36
|
console.log("Transaction:")
|
|
37
|
-
console.log("https://explorer.
|
|
37
|
+
console.log("https://explorer.provable.com/transaction/" + result)
|
|
38
38
|
alert("Transaction ID: " + result);
|
|
39
39
|
} catch (e) {
|
|
40
40
|
console.log(e)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Layout, Menu } from 'antd';
|
|
2
|
+
import { UserOutlined, CrownOutlined } from '@ant-design/icons';
|
|
3
|
+
import { Link, useLocation } from 'react-router-dom';
|
|
4
|
+
|
|
5
|
+
const { Sider } = Layout;
|
|
6
|
+
|
|
7
|
+
export const Sidebar = () => {
|
|
8
|
+
const location = useLocation();
|
|
9
|
+
|
|
10
|
+
const items = [
|
|
11
|
+
{
|
|
12
|
+
key: '/bidder',
|
|
13
|
+
icon: <UserOutlined />,
|
|
14
|
+
label: <Link to="/bidder">Bidder</Link>,
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
key: '/auctioneer',
|
|
18
|
+
icon: <CrownOutlined />,
|
|
19
|
+
label: <Link to="/auctioneer">Auctioneer</Link>,
|
|
20
|
+
}
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Sider
|
|
25
|
+
width={200}
|
|
26
|
+
theme="light"
|
|
27
|
+
style={{
|
|
28
|
+
position: 'fixed',
|
|
29
|
+
left: 0,
|
|
30
|
+
top: 0,
|
|
31
|
+
bottom: 0,
|
|
32
|
+
background: '#ffffff'
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
<Menu
|
|
36
|
+
mode="inline"
|
|
37
|
+
selectedKeys={[location.pathname]}
|
|
38
|
+
style={{
|
|
39
|
+
height: '100%',
|
|
40
|
+
borderRight: '1px solid #f0f0f0',
|
|
41
|
+
background: '#ffffff'
|
|
42
|
+
}}
|
|
43
|
+
items={items}
|
|
44
|
+
/>
|
|
45
|
+
</Sider>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Card, Form, Input, Button, List, Typography, message } from 'antd';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { AleoWorker } from "../workers/AleoWorker";
|
|
4
|
+
|
|
5
|
+
const aleoWorker = AleoWorker();
|
|
6
|
+
|
|
7
|
+
export const AuctioneerPage = () => {
|
|
8
|
+
const [receivedBids, setReceivedBids] = useState([]);
|
|
9
|
+
const [loading, setLoading] = useState(false);
|
|
10
|
+
const [resolveForm] = Form.useForm();
|
|
11
|
+
const [finishForm] = Form.useForm();
|
|
12
|
+
|
|
13
|
+
const layout = {
|
|
14
|
+
labelCol: { span: 6 },
|
|
15
|
+
wrapperCol: { span: 16 },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const handleResolveBids = async (values) => {
|
|
19
|
+
try {
|
|
20
|
+
setLoading(true);
|
|
21
|
+
const result = await aleoWorker.resolveBids(values.bid1, values.bid2);
|
|
22
|
+
message.success('Bids resolved successfully');
|
|
23
|
+
resolveForm.resetFields();
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error('Error resolving bids:', error);
|
|
26
|
+
message.error('Failed to resolve bids');
|
|
27
|
+
} finally {
|
|
28
|
+
setLoading(false);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const handleFinishAuction = async (values) => {
|
|
33
|
+
try {
|
|
34
|
+
setLoading(true);
|
|
35
|
+
const result = await aleoWorker.finishAuction(values.winningBid);
|
|
36
|
+
message.success('Auction finished successfully');
|
|
37
|
+
finishForm.resetFields();
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error('Error finishing auction:', error);
|
|
40
|
+
message.error('Failed to finish auction');
|
|
41
|
+
} finally {
|
|
42
|
+
setLoading(false);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div style={{ padding: '24px', maxWidth: '800px', margin: '0 auto' }}>
|
|
48
|
+
<Typography.Title level={2}>Auction Management</Typography.Title>
|
|
49
|
+
|
|
50
|
+
<Card
|
|
51
|
+
title={<Typography.Title level={4}>Current Auction Bids</Typography.Title>}
|
|
52
|
+
style={{ marginBottom: '24px' }}
|
|
53
|
+
>
|
|
54
|
+
<List
|
|
55
|
+
dataSource={receivedBids}
|
|
56
|
+
renderItem={(bid) => (
|
|
57
|
+
<List.Item>
|
|
58
|
+
<Typography.Text>
|
|
59
|
+
Bid ID: {bid.id} - Amount: {bid.amount}
|
|
60
|
+
</Typography.Text>
|
|
61
|
+
</List.Item>
|
|
62
|
+
)}
|
|
63
|
+
locale={{
|
|
64
|
+
emptyText: <Typography.Text type="secondary">No bids received yet</Typography.Text>
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
</Card>
|
|
68
|
+
|
|
69
|
+
<Card
|
|
70
|
+
title={<Typography.Title level={4}>Compare and Resolve Bids</Typography.Title>}
|
|
71
|
+
style={{ marginBottom: '24px' }}
|
|
72
|
+
>
|
|
73
|
+
<Form
|
|
74
|
+
{...layout}
|
|
75
|
+
form={resolveForm}
|
|
76
|
+
onFinish={handleResolveBids}
|
|
77
|
+
>
|
|
78
|
+
<Form.Item
|
|
79
|
+
label="First Bid Record"
|
|
80
|
+
name="bid1"
|
|
81
|
+
tooltip="Enter the record of the first bid to compare"
|
|
82
|
+
rules={[{ required: true, message: 'Please enter the first bid record' }]}
|
|
83
|
+
>
|
|
84
|
+
<Input.TextArea
|
|
85
|
+
placeholder="Enter the complete bid record"
|
|
86
|
+
rows={3}
|
|
87
|
+
/>
|
|
88
|
+
</Form.Item>
|
|
89
|
+
<Form.Item
|
|
90
|
+
label="Second Bid Record"
|
|
91
|
+
name="bid2"
|
|
92
|
+
tooltip="Enter the record of the second bid to compare"
|
|
93
|
+
rules={[{ required: true, message: 'Please enter the second bid record' }]}
|
|
94
|
+
>
|
|
95
|
+
<Input.TextArea
|
|
96
|
+
placeholder="Enter the complete bid record"
|
|
97
|
+
rows={3}
|
|
98
|
+
/>
|
|
99
|
+
</Form.Item>
|
|
100
|
+
<Form.Item wrapperCol={{ offset: 6, span: 16 }}>
|
|
101
|
+
<Button
|
|
102
|
+
type="primary"
|
|
103
|
+
htmlType="submit"
|
|
104
|
+
loading={loading}
|
|
105
|
+
>
|
|
106
|
+
Compare and Resolve Bids
|
|
107
|
+
</Button>
|
|
108
|
+
</Form.Item>
|
|
109
|
+
</Form>
|
|
110
|
+
</Card>
|
|
111
|
+
|
|
112
|
+
<Card
|
|
113
|
+
title={<Typography.Title level={4}>Finalize Auction</Typography.Title>}
|
|
114
|
+
>
|
|
115
|
+
<Form
|
|
116
|
+
{...layout}
|
|
117
|
+
form={finishForm}
|
|
118
|
+
onFinish={handleFinishAuction}
|
|
119
|
+
>
|
|
120
|
+
<Form.Item
|
|
121
|
+
label="Winning Bid Record"
|
|
122
|
+
name="winningBid"
|
|
123
|
+
tooltip="Enter the record of the winning bid"
|
|
124
|
+
rules={[{ required: true, message: 'Please enter the winning bid record' }]}
|
|
125
|
+
>
|
|
126
|
+
<Input.TextArea
|
|
127
|
+
placeholder="Enter the complete winning bid record"
|
|
128
|
+
rows={3}
|
|
129
|
+
/>
|
|
130
|
+
</Form.Item>
|
|
131
|
+
<Form.Item wrapperCol={{ offset: 6, span: 16 }}>
|
|
132
|
+
<Button
|
|
133
|
+
type="primary"
|
|
134
|
+
htmlType="submit"
|
|
135
|
+
loading={loading}
|
|
136
|
+
>
|
|
137
|
+
Finalize Auction with Winner
|
|
138
|
+
</Button>
|
|
139
|
+
</Form.Item>
|
|
140
|
+
</Form>
|
|
141
|
+
</Card>
|
|
142
|
+
</div>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Card, Form, Input, Button, List, Typography, message } from 'antd';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { AleoWorker } from "../workers/AleoWorker";
|
|
4
|
+
|
|
5
|
+
const aleoWorker = AleoWorker();
|
|
6
|
+
|
|
7
|
+
export const BidderPage = () => {
|
|
8
|
+
const [account, setAccount] = useState(null);
|
|
9
|
+
const [bids, setBids] = useState([]);
|
|
10
|
+
const [loading, setLoading] = useState(false);
|
|
11
|
+
const [bidForm] = Form.useForm();
|
|
12
|
+
|
|
13
|
+
const layout = {
|
|
14
|
+
labelCol: { span: 4 },
|
|
15
|
+
wrapperCol: { span: 20 },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const handleSetAccount = async (value) => {
|
|
19
|
+
try {
|
|
20
|
+
setLoading(true);
|
|
21
|
+
await aleoWorker.setAccount(value);
|
|
22
|
+
setAccount(value);
|
|
23
|
+
message.success('Account set successfully');
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error('Error setting account:', error);
|
|
26
|
+
message.error('Failed to set account');
|
|
27
|
+
setAccount(null);
|
|
28
|
+
} finally {
|
|
29
|
+
setLoading(false);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const handlePlaceBid = async (values) => {
|
|
34
|
+
if (!account) {
|
|
35
|
+
message.error('Please set your account first');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
setLoading(true);
|
|
41
|
+
const result = await aleoWorker.placeBid(values.amount, values.auctionId);
|
|
42
|
+
message.success('Bid placed successfully');
|
|
43
|
+
bidForm.resetFields();
|
|
44
|
+
|
|
45
|
+
// Add the new bid to the list
|
|
46
|
+
setBids(prevBids => [...prevBids, {
|
|
47
|
+
auctionId: values.auctionId,
|
|
48
|
+
amount: values.amount,
|
|
49
|
+
id: result.id // Assuming the worker returns a bid ID
|
|
50
|
+
}]);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('Error placing bid:', error);
|
|
53
|
+
message.error('Failed to place bid');
|
|
54
|
+
} finally {
|
|
55
|
+
setLoading(false);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div style={{ padding: '24px' }}>
|
|
61
|
+
<Card
|
|
62
|
+
title="Aleo Account"
|
|
63
|
+
style={{ marginBottom: '24px' }}
|
|
64
|
+
>
|
|
65
|
+
<Form {...layout}>
|
|
66
|
+
<Form.Item
|
|
67
|
+
label="Private Key"
|
|
68
|
+
required
|
|
69
|
+
tooltip="Your Aleo private key is required to place bids"
|
|
70
|
+
>
|
|
71
|
+
<Input.Password
|
|
72
|
+
placeholder="Enter your Aleo private key"
|
|
73
|
+
onChange={(e) => handleSetAccount(e.target.value)}
|
|
74
|
+
value={account}
|
|
75
|
+
disabled={loading}
|
|
76
|
+
/>
|
|
77
|
+
</Form.Item>
|
|
78
|
+
{account && (
|
|
79
|
+
<Form.Item wrapperCol={{ offset: 4 }}>
|
|
80
|
+
<Typography.Text type="success">
|
|
81
|
+
Account set ✓
|
|
82
|
+
</Typography.Text>
|
|
83
|
+
</Form.Item>
|
|
84
|
+
)}
|
|
85
|
+
</Form>
|
|
86
|
+
</Card>
|
|
87
|
+
|
|
88
|
+
<Card
|
|
89
|
+
title="Place Bid"
|
|
90
|
+
style={{ marginBottom: '24px' }}
|
|
91
|
+
>
|
|
92
|
+
<Form
|
|
93
|
+
{...layout}
|
|
94
|
+
form={bidForm}
|
|
95
|
+
onFinish={handlePlaceBid}
|
|
96
|
+
>
|
|
97
|
+
<Form.Item
|
|
98
|
+
label="Amount"
|
|
99
|
+
name="amount"
|
|
100
|
+
rules={[
|
|
101
|
+
{ required: true, message: 'Please enter bid amount' },
|
|
102
|
+
{ pattern: /^\d+$/, message: 'Please enter a valid number' }
|
|
103
|
+
]}
|
|
104
|
+
>
|
|
105
|
+
<Input placeholder="Enter bid amount" disabled={!account || loading} />
|
|
106
|
+
</Form.Item>
|
|
107
|
+
<Form.Item
|
|
108
|
+
label="Auction ID"
|
|
109
|
+
name="auctionId"
|
|
110
|
+
rules={[{ required: true, message: 'Please enter auction ID' }]}
|
|
111
|
+
>
|
|
112
|
+
<Input placeholder="Enter auction ID" disabled={!account || loading} />
|
|
113
|
+
</Form.Item>
|
|
114
|
+
<Form.Item wrapperCol={{ offset: 4 }}>
|
|
115
|
+
<Button
|
|
116
|
+
type="primary"
|
|
117
|
+
htmlType="submit"
|
|
118
|
+
loading={loading}
|
|
119
|
+
disabled={!account}
|
|
120
|
+
>
|
|
121
|
+
Submit Bid
|
|
122
|
+
</Button>
|
|
123
|
+
</Form.Item>
|
|
124
|
+
</Form>
|
|
125
|
+
</Card>
|
|
126
|
+
|
|
127
|
+
<Card title="Open Bids">
|
|
128
|
+
<List
|
|
129
|
+
dataSource={bids}
|
|
130
|
+
renderItem={(bid) => (
|
|
131
|
+
<List.Item>
|
|
132
|
+
<Typography.Text>
|
|
133
|
+
Auction ID: {bid.auctionId} - Amount: {bid.amount}
|
|
134
|
+
</Typography.Text>
|
|
135
|
+
</List.Item>
|
|
136
|
+
)}
|
|
137
|
+
locale={{ emptyText: 'No bids placed yet' }}
|
|
138
|
+
/>
|
|
139
|
+
</Card>
|
|
140
|
+
</div>
|
|
141
|
+
);
|
|
142
|
+
};
|
package/template-vanilla/main.js
CHANGED
|
@@ -39,7 +39,7 @@ document.querySelector("#app").innerHTML = `
|
|
|
39
39
|
<div class="card">
|
|
40
40
|
<button onclick="window.execute()">Call Execute Function</button>
|
|
41
41
|
<button onclick="window.key()">Get Private Key</button>
|
|
42
|
-
<button onclick="window.deploy()">Deploy
|
|
42
|
+
<button onclick="window.deploy()">Deploy Hello World Program</button>
|
|
43
43
|
</div>
|
|
44
44
|
<p class="read-the-docs">
|
|
45
45
|
Click on the Aleo logo to learn more
|