bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 41쪽 중 23쪽
f-deploy
-a
$WALLET_ADDRESS
-p
$WALLET_PASSWORD
-c
$CONTRACT_PATH
-e
https://tdvw-test-node.aelf.io/
Command Prompt
$CONTRACT_PATH
=
Get-ChildItem
-Recurse
-Filter
"*patched*"
|
Select-Object
-First
1
-ExpandProperty
FullName
$env
:CONTRACT_PATH
=
$CONTRACT_PATH
Command Prompt
aelf-deploy
-a
$env
:WALLET_ADDRESS
-p
$env
:WALLET_PASSWORD
-c
$env
:CONTRACT_PATH
-e
https://tdvw-test-node.aelf.io/
Please wait for approximately 1 to 2 minutes. If the deployment is successful, it will provide you with the contract address.
Copy the smart contract address from the
address
field
Export your smart contract address:
Linux and macOs
Windows
Terminal
export
CONTRACT_ADDRESS
=
"YOUR_SMART_CONTRACT_ADDRESS e.g. 2LUmicHyH4RXrMjG4beDwuDsiWJESyLkgkwPdGTR8kahRzq5XS"
Command Prompt
$env
:CONTRACT_ADDRESS
=
"YOUR_SMART_CONTRACT_ADDRESS e.g. 2LUmicHyH4RXrMjG4beDwuDsiWJESyLkgkwPdGTR8kahRzq5XS"
tip
ℹ️ Note: You are to copy the smart contract address as we will be referencing it in the next steps!
info
🎉 You have successfully deployed your Expense Tracker dApp smart contract on the aelf testnet! In the next steps, we will be building the frontend components that allow us to interact with our deployed smart contract!
Step 4 - Interact with Your Deployed Smart Contract through dApp
Project Setup
Let's start by cloning the frontend project repository from github.
Terminal
git
clone https://github.com/AElfProject/aelf-samples.git
Next, navigate to the frontend project directory with this command:
Terminal
cd
aelf-samples/expense-tracker/2-dapp
Once you're inside the
2-dapp
directory, open the project with your preferred IDE (e.g., VSCode). You should see the project structure as shown below.
Install necessary libraries
Run this command in the terminal to install all necessary packages and libraries:
Terminal
npm
install
We are now ready to build the frontend components of our Expense-Tracker dApp.
Configure Portkey Provider & Write Connect Wallet Function
Now, we'll set up our Portkey wallet provider to allow users to connect their Portkey wallets to the dApp and interact with the smart contract. We'll be interacting with the already deployed Expense Tracker smart contract for this tutorial.
Step 1. Locate the File:
Go to the
src/hooks/useExpenseTrackerSmartContract.ts
file.
Step 2. Fetch the Smart Contract:
Find the comment
//Step A - Function to fetch a smart contract based on deployed wallet address
Replace the existing
fetchContract
function with this updated code:
useExpenseTrackerSmartContract.ts
//Step A - Function to fetch a smart contract based on deployed wallet address
const
fetchContract
=
async
(
)
=>
{
if
(
!
provider
)
return
null
;
try
{
// 1. get the aelf dAppChain using provider.getChain
const
chain
=
await
provider
?.
getChain
(
"tDVW"
)
;
if
(
!
chain
)
throw
new
Error
(
"No chain"
)
;
//Address of Expense Tracker Smart Contract
//Replace with Address of Deployed Smart Contract
const
address
=
"your_deployed_expense_tracker_contract_address"
;
// 2. get the Expense Tracker contract
const
contract
=
chain
?.
getContract
(
address
)
;
setSmartContract
(
contract
)
;
}
catch
(
error
)
{
console
.
log
(
error
,
"====error"
)
;
}
}
;
tip
ℹ️ Note: You are to replace the address placeholder with your deployed Expense Tracker smart contract address from "Deploy Smart Contract" step!
example: Replace with Address of Deployed Smart Contract
const address = "your_deployed_expense_tracker_contract_address";
Explanation:
fetchContract
Function
: This function fetches a smart contract based on the given chain symbol (e.g., "AELF" or "tDVW") and the contract address.
Check Provider
: If no provider is available, the function returns null.
Fetch Chain
: The function fetches chain information using the provider.
Get Contract
: It retrieves the smart contract instance from the chain.
AELF
represents the mainnet chain and
tDVW
represents the testnet chain respectively on the aelf blockchain.
Step 3. Initialize and Fetch the Smart Contracts:
Find the comment
// Step B - Effect hook to initialize and fetch the smart contract when the provider changes.
Replace the existing
useEffect
hook with this updated code:
useSmartContract.ts
// Step B - Effect hook to initialize and fetch the smart contract when the provider changes
useEffect
(
(
)
=>
{
fetchContract
(
)
;
}
,
[
provider
]
)
;
// Dependency array ensures this runs when the provider changes
Explanation:
useEffect
Hook
: This hook initializes and fetches the smart contracts when the provider changes.
Check Provider
: If no provider is available, the function returns null.
Fetch Contracts
: It fetches and sets the smart contracts.
By following these steps, we'll configure the Portkey provider to connect users' wallets to our app and interact with the Expense Tracker smart contract which includes the tracking and management of expenses functionalities. This setup will enable our frontend components to perform actions like
addNewExpense
,
updateExpense
,
deleteExpense
and
getExpenseData
etc.
Configure Connect Wallet Function
Step 1: Locate the File
Go to the
src/components/layout/header/index.tsx
file.
Step 2: Write the Connect Wallet Function
The
header/index.tsx
file is the header of our Expense Tracker dApp. It allows users to connect their Portkey wallet with the Expense Tracker dApp.
Before users can interact with the smart contract, we need to write the
Connect Wallet
function.
Find the comment
// Step C - Connect Portkey Wallet
.
Replace the existing
connect
function with this code snippet:
header/index.tsx
const
connect
=
async
(
walletProvider
?
:
IPortkeyProvider
)
=>
{
// Step C - Connect Portkey Wallet
const
accounts
=
await
(
walletProvider
?
walletProvider
:
provider
)
?.
request
(
{
method
:
MethodsBase
.
REQUEST_ACCOUNTS
,
}
)
;
const
account
=
accounts
?.
AELF
&&
accounts
?.
AELF
[
0
]
;
if
(
account
)
{
setCurrentWalletAddress
(
account
.
replace
(
/
^
ELF_
/
,
""
)
.
replace
(
/
_AELF
$
/
,
""
)
)
;
setIsConnected
(
true
)
;
}
!
walletProvider
&&
toast
.
success
(
"Successfully connected"
)
;
}
;
Explanation:
connect
Function
: This function connects the user's Portkey wallet with the dApp.
Fetch Accounts
: It fetches the wallet accounts using the provider.
Log Accounts
: Logs the accounts to the console for debugging.
Set Wallet Address
: Sets the current wallet address state variable with the fetched account.
In this code, we fetch the Portkey wallet account using the provider and update the wallet address state variable. An alert notifies the user that their wallet is successfully connected.
With the connect wallet function defined, we're ready to write the remaining functions in the next steps.
Configure Create Expense Form
Step 1: Locate the File
Go to the
src/pages/home/index.tsx
file. This file contains all the functionalities like show user's Expense, AddExpense, UpdateExpense, DeleteExpense, etc.
Step 2: Prepare Form to Add and Update Expenses
Find the comment
// Step D - Configure Expense Form
.
Replace the form variable with this code snippet:
home/index.tsx
// Step D - Configure Expense Form
const
form
=
useForm
<
z
.
infer
<
typeof
formSchema
>>
(
{
resolver
:
zodResolver
(
formSchema
)
,
defaultValues
:
{
description
:
""
,
amount
:
""
,
}
,
}
)
;
Here's what the function does:
Initializes a new form variable with default values needed to add a new expense.
Fields include:
description
and
amount
.
Now the form is ready for users to fill in the necessary details.
Check Contract Initialization
Step 1: Locate the File
Go to the
src/pages/home/index.tsx
file. This file contains all the functionalities like
checkIsContractInitialized
,
initializeContract
,
addNewExpense
,
updateExpense
,
deleteExpense
and
getExpenseData
.
Step 2: Prepare a Function to Check Whether the Contract is Initialized or not
Scroll down to find the comment
// step 1 - Check If Contract is Initialized or not
.
Replace the existing
checkIsContractInitialized
function with this code snippet:
home/index.tsx
// step 1 - Check If Contract is Initialized or not
const
checkIsContractInitialized
=
async
(
)
=>
{
const
result
=
await
smartContract
?.
callViewMethod
(
"GetInitialStatus"
,
""
)
;
// Call the GetInitialStatus method which is present on Smart Contract
setIsContractInitialized
(
result
?.
data
?.
value
)
;
// Expect value True if it's Initialized otherwise NULL if it's not
}
;
Initialize Contract
Scroll down to find the comment
// step 2 - Initialize the smart contract
.
Replace the existing
checkIsContractInitialized
function with this code snippet:
home/index.tsx
// step 2 - Initialize the smart contract
const
initializeContract
=
async
(
)
=>
{
let
initializeLoadingId
;
try
{
// Start Loading
initializeLoadingId
=
toast
.
loading
(
"Initializing a Contract.."
)
;
await
smartContract
?.
callSendMethod
(
"Initialize"
,
// Function Name
currentWalletAddress
as
string
,
// User Wallet Address
{
}
// No Arguments
)
;
// Update Loading Message with Success
toast
.
update
(
initializeLoadingId
,
{
render
:
"Contract Successfully Initialized"
,
type
:
"success"
,
isLoading
:
false
,
}
)
;
return
;
}
catch
(
error
:
any
)
{
// Update Loading Message with Error
toast
.
update
(
initializeLoadingId
as
Id
,
{
render
:
error
.
message
,
type
:
"error"
,
isLoading
:
false
,
}
)
;
return
;
}
finally
{
// Remove Loading Message
removeNotification
(
initializeLoadingId
as
Id
)
;
}
}
;
Add New Expense
Write the function to add a new expense.
Find the comment
// step 3 - Add a New Expense using Smart Contract
.
Replace the existing
addNewExpense
function with this code snippet:
home/index.tsx
// step 3 - Add a New Expense using Smart Contract
const
addNewExpense
=
async
(
values
:
{
description
:
string
;
amount
:
string
;
}
)
=>
{
let
addLoadingId
;
try
{
// Start Loading
addLoadingId
=
toast
.
loading
(
"Adding a New Expense.."
)
;
setFormLoading
(
true
)
;
// Prepare Arguments for Create a New Expense
const
sendData
=
{
description
:
values
.
description
,
amount
:
values
.
amount
,
category
:
selectedCategory
?.
value
,
currency
:
"USD"
,
}
;
// Call AddExpense Function of Smart Contract
await
smartContract
?.
callSendMethod
(
"AddExpense"
,
currentWalletAddress
as
string
,
sendData
)
;
// Update Loading Message with Success
toast
.
update
(
addLoadingId
,
{
render
:
"New Expense Successfully Adding"
,
type
:
"success"
,
isLoading
:
false
,
}
)
;
// Get New Data from Contract
getExpenseData
(
)
;
}
catch
(
error
:
any
)
{
// Update Loading Message with Error
toast
.
update
(
addLoadingId
as
Id
,
{
render
:
error
.
message
,
type
:
"error"
,
isLoading
:
false
,
}
)
;
}
finally
{
// Close Form Modal
handleCloseModal
(
)
;
// Remove Loading Message
removeNotification
(
addLoadingId
as
Id
)
;
setFormLoading
(
false
)
;
}
}
;
What This Function Does:
Calls Smart Contract Method
: It interacts with the aelf blockchain's smart contract to add a new Expense using
AddExpense
Function.
Next, we'll write the
Update Expense
function.
Update Expense
Write the function to update a selected expense.
Scroll down to find the comment
// step 4 - Update the Expense
.
Replace the existing
updateExpense
function with this code snippet:
home/index.tsx
// step 4 - Update the Expense
const
updateExpense
=
async
(
values
:
{
description
:
string
;
amount
:
string
;
}
)
=>
{
let
updateLoadingId
;
try
{
// Start Loading
updateLoadingId
=
toast
.
loading
(
"Updating a Expense.."
)
;
setFormLoading
(
true
)
;
// Prepare Arguments for Update the Expense
const
sendData
=
{
expenseId
:
updateId
,
description
:
values
.
description
,
amount
:
values
.
amount
,
category
:
selectedCategory
?.
value
,
currency
:
"USD"
,
}
;
// Call UpdateExpense Function of Smart Contract
await
smartContract
?.
callSendMethod
(
"UpdateExpense"
,
currentWalletAddress
as
string
,
sendData
)
;
// Update Loading Message with Success
toast
.
update
(
updateLoadingId
,
{
render
:
"Expense Successfully Updated"
,
type
:
"success"
,
isLoading
:
false
,
}
)
;
// Get New Data from Contract
getExpenseData
(
)
;
}
catch
(
error
:
any
)
{
// Update Loading Message with Error
toast
.
update
(
updateLoadingId
as
Id
,
{
render
:
error
.
message
,
type
:
"error"
,
isLoading
:
false
,
}
)
;
}
finally
{
// Close Form Modal
handleCloseModal
(
)
;
// Remove Loading Message
removeNotification
(
updateLoadingId
as
Id
)
;
setFormLoading
(
false
)
;
}
}
;
What This Function Does:
Calls Smart Contract Method
: It interacts with the blockchain smart contract to Update the existing expense using
UpdateExpense
function.
Get New Data from Contract
: It calls the
getExpenseData
function to get updated data from the smart contract.
Next, we'll write the
Delete Expense
function.
Delete Expense
Write the Function to delete an existing expense.
Scroll down to find the comment
// step 5 - Delete the Expense
.
Replace the existing
deleteExpense
function with the following code snippet:
home/index.tsx
// step 5 - Delete the Expense
const
deleteExpense
=
async
(
data
:
IExpenseObject
)
=>
{
let
deleteLoadingId
;
try
{
// Start Loading
deleteLoadingId
=
toast
.
loading
(
"Removing a Expense.."
)
;
setDeletingId
(
data
.
expenseId
)
;
// set Deleting Id for Loading on Button
// Call DeleteExpense Function of Smart Contract for Delete the Expense
await
smartContract
?.
callSendMethod
(
"DeleteExpense"
,
currentWalletAddress
as
string
,
{
value
:
data
.
expenseId
}
)
;
// Update Loading Message with Success
toast
.
update
(
deleteLoadingId
,
{
render
:
"Expense Successfully Removed"
,
type
:
"success"
,
isLoading
:
false
,
}
)
;
// Get New Data from Contract
await
getExpenseData
(
)
;
}
catch
(
error
:
any
)
{
// Update Loading Message with Error
toast
.
update
(
deleteLoadingId
as
Id
,
{
render
:
error
.
message
,
type
:
"error"
,
isLoading
:
false
,
}
)
;
}
finally
{
setDeletingId
(
null
)
;
// Remove Loading Message
removeNotification
(
deleteLoadingId
as
Id
)
;
}
}
;
What This Function Does:
Calls Smart Contract Method
: It interacts with the blockchain smart contract to delete an existing expense using the
DeleteExpense
function.
Get New Data from Contract
: It calls the
getExpenseData
function to get updated data from the smart contract.
Next, we'll write the
Handle Submit Form
function.
Handle Submit Form
Write a function to make the move.
Scroll down to find the comment
// step 6 - Handle Submit Form
.
Replace the existing
onSubmit
function with this code snippet:
home/index.tsx
// step 6 - Handle Submit Form
const
onSubmit
=
async
(
values
:
{
description
:
string
,
amount
:
string
}
)
=>
{
// Check Whether Contract Initialized or not
if
(
isContractInitialized
!==
true
)
{
await
initializeContract
(
)
;
// initialize the contract if it's not initialized before
}
// Check Whether Form is for Create or Update the Expense
if
(
!
!
updateId
)
{
await
updateExpense
(
values
)
;
// Call updateExpense for Update the Expense
}
else
{
await
addNewExpense
(
values
)
;
// Call updateExpense for Create a new Expense
}
}
;
What This Function Does:
Check initialized contract
: It checks whether the smart contract is initialized or not by using
initializeContract
function.
Update Expense
: Call the
updateExpense
function if updatedId has any value.
Add Expense
: Call the
addNewExpense
function if updatedId does not have any value.
Here, we have completed functions to
Add Expense
,
Update Expense
and
Delete Expense
and now it's time to write a function to
Fetch Expense
from the smart contract.
Fetch All Expenses
Scroll up to find the comment
// step 7 - Fetch All Expenses
.
Replace the existing
getExpenseData
function with this code snippet:
home/index.tsx
// step 7 - Fetch All Expenses
const
getExpenseData
=
async
(
)
=>
{
try
{
const
result
=
await
smartContract
?.
callViewMethod
(
"ListExpenses"
,
{
value
:
currentWalletAddress
,
}
)
;
console
.
log
(
"result"
,
result
?.
data
)
;
setExpenseData
(
result
?.
data
?
result
?.
data
.
expenses
:
[
]
)
;
}
catch
(
error
)
{
console
.
log
(
"error======"
,
error
)
;
}
finally
{
setLoading
(
false
)
;
}
}
;
Here's what the function does:
Fetches Expense Data:
It calls
ListExpenses
to get the list of all expenses from the Expense Tracker smart contract.
Set Expense on State:
Get the result data from the smart contract and set an array of all expenses into
expenseData
State.
We have prepared necessary function to fetch all the expenses created from a connected user's wallet.
Now that we've written all the necessary frontend functions and components, we're ready to run the Expense Tracker dApp application in the next step.
Run Application
In this step, we will run the Expense Tracker dApp application.
To begin, run the following command on your terminal.
Terminal
npm
run dev
info
Note
: Ensure that you are running this command under the
expense-tracker/2-dapp
folder.
You should observe the following as shown below.
Upon clicking on the
localhost URL
, you should be directed to the Expense Tracker dApp landing page as shown below.
tip
If you are developing and testing this with github codespace, you can use
port forward
to test the web server that is running in codespace, here is the link on how to use
port forward
for codespace
https://docs.github.com/en/codespaces/developing-in-a-codespace/forwarding-ports-in-your-codespace
Usually codespaces automatically forward ports, you should see a pop-up message at the bottom right of your codespace browser window as shown in the diagram below:
Click the link to open the Expense Tracker dApp in the browser.
Create Portkey Wallet
info
Portkey is the first AA wallet from aelf's ecosystem, migrating users, developers and projects from Web2 to Web3 with DID solution.
Users can swiftly log into Portkey via their Web2 social info with no private keys or mnemonics required. Underpinned by social recovery and decentralized guardian design, Portkey safeguards users' assets from centralized control and theft. Portkey has a unique payment delegation mechanism which enables interested parties to function as delegatees to pay for user activities on users' behalf. This means that users can create accounts for free and fees for other usages may also be covered in Portkey.
Portkey also provides crypto on/off-ramp services, allowing users to exchange fiat with crypto freely. It supports the storage and management of various digital assets such as tokens, NFTs, etc. The compatibility with multi-chains and seamless connection to all kinds of DApps makes Portkey a great way to enter the world of Web3.
With DID solution as its core, Portkey provides both Portkey Wallet and Portkey SDKs.
For more information, you may visit the official documentation for Portkey at
https://doc.portkey.finance/
.
Download the Chrome extension for Portkey from
https://chromewebstore.google.com/detail/portkey-wallet/iglbgmakmggfkoidiagnhknlndljlolb
.
info
The Portkey extension supports Chrome browser only (for now). Please ensure that you are using Chrome browser.
You may download Chrome from
https://www.google.com/intl/en_sg/chrome/
.
Once you have downloaded the extension, you should see the following on your browser as shown below.
Click on
Get Start
and you should see the following interface as shown below.
Sign up
Switch to
ael프로젝트로 돌아가기