bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 41쪽 중 26쪽
// The contract address.
aelf
.
Address
contract_address
=
1
;
// Resource tokens to charge.
TotalResourceTokensMap
tokens_map
=
2
;
}
message
TotalResourceTokensMap
{
// Resource token dictionary, Symbol->Amount.
map
<
string
,
int64
>
value
=
1
;
}
message
StringList
{
repeated
string
value
=
1
;
}
message
TransactionFeeDelegations
{
// delegation, symbols and its' amount
map
<
string
,
int64
>
delegations
=
1
;
// height when added
int64
block_height
=
2
;
//Whether to pay transaction fee continuously
bool
isUnlimitedDelegate
=
3
;
}
message
TransactionFeeDelegatees
{
map
<
string
,
TransactionFeeDelegations
>
delegatees
=
1
;
}
message
SetTransactionFeeDelegationsInput
{
// the delegator address
aelf
.
Address
delegator_address
=
1
;
// delegation, symbols and its' amount
map
<
string
,
int64
>
delegations
=
2
;
}
message
SetTransactionFeeDelegationsOutput
{
bool
success
=
1
;
}
message
RemoveTransactionFeeDelegatorInput
{
// the delegator address
aelf
.
Address
delegator_address
=
1
;
}
message
RemoveTransactionFeeDelegateeInput
{
// the delegatee address
aelf
.
Address
delegatee_address
=
1
;
}
message
GetTransactionFeeDelegationsOfADelegateeInput
{
aelf
.
Address
delegatee_address
=
1
;
aelf
.
Address
delegator_address
=
2
;
}
message
GetTransactionFeeDelegateesInput
{
aelf
.
Address
delegator_address
=
1
;
}
message
GetTransactionFeeDelegateesOutput
{
repeated
aelf
.
Address
delegatee_addresses
=
1
;
}
message
SetSymbolAliasInput
{
string
symbol
=
1
;
string
alias
=
2
;
}
// Events
message
Transferred
{
option
(
aelf
.
is_event
)
=
true
;
// The source address of the transferred token.
aelf
.
Address
from
=
1
[
(
aelf
.
is_indexed
)
=
true
]
;
// The destination address of the transferred token.
aelf
.
Address
to
=
2
[
(
aelf
.
is_indexed
)
=
true
]
;
// The symbol of the transferred token.
string
symbol
=
3
[
(
aelf
.
is_indexed
)
=
true
]
;
// The amount of the transferred token.
int64
amount
=
4
;
// The memo.
string
memo
=
5
;
}
message
Approved
{
option
(
aelf
.
is_event
)
=
true
;
// The address of the token owner.
aelf
.
Address
owner
=
1
[
(
aelf
.
is_indexed
)
=
true
]
;
// The address that allowance be increased.
aelf
.
Address
spender
=
2
[
(
aelf
.
is_indexed
)
=
true
]
;
// The symbol of approved token.
string
symbol
=
3
[
(
aelf
.
is_indexed
)
=
true
]
;
// The amount of approved token.
int64
amount
=
4
;
}
message
UnApproved
{
option
(
aelf
.
is_event
)
=
true
;
// The address of the token owner.
aelf
.
Address
owner
=
1
[
(
aelf
.
is_indexed
)
=
true
]
;
// The address that allowance be decreased.
aelf
.
Address
spender
=
2
[
(
aelf
.
is_indexed
)
=
true
]
;
// The symbol of un-approved token.
string
symbol
=
3
[
(
aelf
.
is_indexed
)
=
true
]
;
// The amount of un-approved token.
int64
amount
=
4
;
}
message
Burned
{
option
(
aelf
.
is_event
)
=
true
;
// The address who wants to burn token.
aelf
.
Address
burner
=
1
[
(
aelf
.
is_indexed
)
=
true
]
;
// The symbol of burned token.
string
symbol
=
2
[
(
aelf
.
is_indexed
)
=
true
]
;
// The amount of burned token.
int64
amount
=
3
;
}
message
ChainPrimaryTokenSymbolSet
{
option
(
aelf
.
is_event
)
=
true
;
// The symbol of token.
string
token_symbol
=
1
;
}
message
CalculateFeeAlgorithmUpdated
{
option
(
aelf
.
is_event
)
=
true
;
// All calculate fee coefficients after modification.
AllCalculateFeeCoefficients
all_type_fee_coefficients
=
1
;
}
message
RentalCharged
{
option
(
aelf
.
is_event
)
=
true
;
// The symbol of rental fee charged.
string
symbol
=
1
;
// The amount of rental fee charged.
int64
amount
=
2
;
// The payer of rental fee.
aelf
.
Address
payer
=
3
;
// The receiver of rental fee.
aelf
.
Address
receiver
=
4
;
}
message
RentalAccountBalanceInsufficient
{
option
(
aelf
.
is_event
)
=
true
;
// The symbol of insufficient rental account balance.
string
symbol
=
1
;
// The balance of the account.
int64
amount
=
2
;
}
message
TokenCreated
{
option
(
aelf
.
is_event
)
=
true
;
// The symbol of the token.
string
symbol
=
1
;
// The full name of the token.
string
token_name
=
2
;
// The total supply of the token.
int64
total_supply
=
3
;
// The precision of the token.
int32
decimals
=
4
;
// The address that has permission to issue the token.
aelf
.
Address
issuer
=
5
;
// A flag indicating if this token is burnable.
bool
is_burnable
=
6
;
// The chain id of the token.
int32
issue_chain_id
=
7
;
// The external information of the token.
ExternalInfo
external_info
=
8
;
// The address that owns the token.
aelf
.
Address
owner
=
9
;
}
message
Issued
{
option
(
aelf
.
is_event
)
=
true
;
// The symbol of issued token.
string
symbol
=
1
;
// The amount of issued token.
int64
amount
=
2
;
// The memo.
string
memo
=
3
;
// The issued target address.
aelf
.
Address
to
=
4
;
}
message
CrossChainTransferred
{
option
(
aelf
.
is_event
)
=
true
;
// The source address of the transferred token.
aelf
.
Address
from
=
1
;
// The destination address of the transferred token.
aelf
.
Address
to
=
2
;
// The symbol of the transferred token.
string
symbol
=
3
;
// The amount of the transferred token.
int64
amount
=
4
;
// The memo.
string
memo
=
5
;
// The destination chain id.
int32
to_chain_id
=
6
;
// The chain id of the token.
int32
issue_chain_id
=
7
;
}
message
CrossChainReceived
{
option
(
aelf
.
is_event
)
=
true
;
// The source address of the transferred token.
aelf
.
Address
from
=
1
;
// The destination address of the transferred token.
aelf
.
Address
to
=
2
;
// The symbol of the received token.
string
symbol
=
3
;
// The amount of the received token.
int64
amount
=
4
;
// The memo.
string
memo
=
5
;
// The destination chain id.
int32
from_chain_id
=
6
;
// The chain id of the token.
int32
issue_chain_id
=
7
;
// The parent chain height of the transfer transaction.
int64
parent_chain_height
=
8
;
// The id of transfer transaction.
aelf
.
Hash
transfer_transaction_id
=
9
;
}
message
TransactionFeeDelegationAdded
{
option
(
aelf
.
is_event
)
=
true
;
aelf
.
Address
delegator
=
1
[
(
aelf
.
is_indexed
)
=
true
]
;
aelf
.
Address
delegatee
=
2
[
(
aelf
.
is_indexed
)
=
true
]
;
aelf
.
Address
caller
=
3
[
(
aelf
.
is_indexed
)
=
true
]
;
}
message
TransactionFeeDelegationCancelled
{
option
(
aelf
.
is_event
)
=
true
;
aelf
.
Address
delegator
=
1
[
(
aelf
.
is_indexed
)
=
true
]
;
aelf
.
Address
delegatee
=
2
[
(
aelf
.
is_indexed
)
=
true
]
;
aelf
.
Address
caller
=
3
[
(
aelf
.
is_indexed
)
=
true
]
;
}
message
SymbolAliasAdded
{
option
(
aelf
.
is_event
)
=
true
;
string
symbol
=
1
[
(
aelf
.
is_indexed
)
=
true
]
;
string
alias
=
2
[
(
aelf
.
is_indexed
)
=
true
]
;
}
message
SymbolAliasDeleted
{
option
(
aelf
.
is_event
)
=
true
;
string
symbol
=
1
[
(
aelf
.
is_indexed
)
=
true
]
;
string
alias
=
2
[
(
aelf
.
is_indexed
)
=
true
]
;
}
Building Smart Contract
Build the smart contract code with the following command inside
src
folder:
Terminal
dotnet build
You should see
SinglePoolStaking.dll.patched
in the directory
SinglePoolStaking/src/bin/Debug/net.8.0
Step 3 - Deploy Smart Contract
Create A Wallet
To send transactions on the aelf blockchain, you must have a wallet.
Run this command to create aelf wallet.
Terminal
aelf-command create
You will be prompted to save your account, please do
save
your account as shown below:
Terminal
? Save account info into a file?
(
Y/n
)
Y
Make sure to choose Y to save your account information.
tip
ℹ️ Note: If you do not save your account information (by selecting n or N), do not export the wallet password. Only
proceed to the next
step if you have saved your account information.
Next, enter and confirm your password. Then export your wallet password as shown below:
Linux and macOs
Windows
Terminal
export
WALLET_PASSWORD
=
"YOUR_WALLET_PASSWORD"
Command Prompt
$env
:WALLET_PASSWORD
=
"YOUR_WALLET_PASSWORD"
Acquire Testnet Tokens (Faucet) for Development
To deploy smart contracts or execute on-chain transactions on aelf, you'll require testnet ELF tokens.
Get ELF Tokens
Go to
https://faucet-ui.aelf.dev
Enter your address and click
Get Tokens
.
Deploy Smart Contract:
The smart contract needs to be deployed on the chain before users can interact with it.
Run the following command to deploy a contract. Remember to export the path of SinglePoolStaking.dll.patched to CONTRACT_PATH.
Linux and macOs
Windows
Terminal
export
CONTRACT_PATH
=
$(
find
~+
.
-path
"*patched*"
|
head
-n
1
)
Terminal
aelf-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 Single Pool Staking 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 - Getting TOKEN Seed
In order to create a fungible token on the aelf blockchain, the deployer wallet must have a
TOKEN SEED
.
Visit
TOKEN Faucet
to get your TOKEN SEED.
After the request is successfully processed, the requestor wallet will receive the
SEED
.
Please note this
SEED
symbol value separately as it will be needed while creating the fungible token and staking integration. This will become our
Token Symbol
.
Step 5 - Interact with Your Deployed Smart Contracts
Project Setup
Let's start by cloning the frontend project repository from github.
Run the following command in your Terminal:
Terminal
git
clone https://github.com/AElfProject/aelf-samples.git
Next, navigate to the staking frontend project directory with this command:
Terminal
cd
aelf-samples/staking/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 packages and libraries
Run this command in the terminal to install all necessary packages and libraries.
Linux and macOs
Windows
Terminal
sudo
npm
install
Command Prompt
npm
install
We are now ready to build the frontend components of our Staking dApp.
Configure Portkey Provider & Write Contract Hooks Function
We'll set up our Portkey provider to allow users to connect their Portkey wallets to the dApp and interact with the aelf smart contracts. We'll be interacting with the Stakinng contract and the Multi-token contract.
Write Functions for MainChain and dAppChain Contracts
Step 1. Locate the File:
Go to the
src/hooks/useSmartContract.ts
file.
Step 2. Fetch the Smart Contract:
Find the comment
//Step A - Function to fetch a smart contract based on the chain symbol and the contract address
Replace the existing
fetchContract
function with the below code:
useSmartContract.ts
//Step A - Function to fetch a smart contract based on the chain symbol and the contract address
const
fetchContract
=
async
(
symbol
:
"AELF"
|
"tDVW"
,
contractAddress
:
string
)
=>
{
try
{
// If no provider is available, return null
if
(
!
provider
)
return
null
;
// Fetch the chain information using the provider
const
chain
=
await
provider
.
getChain
(
symbol
)
;
if
(
!
chain
)
throw
new
Error
(
"Chain not found"
)
;
// Get the smart contract instance from the chain
const
contract
=
chain
.
getContract
(
contractAddress
)
;
// Return the smart contract instance
return
contract
;
}
catch
(
error
)
{
console
.
error
(
"Error in fetchContract"
,
{
symbol
,
contractAddress
,
error
}
)
;
}
}
;
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
: This function fetches chain information using the provider.
Get Contract
: It retrieves the smart contract instance from the chain.
Step 3. Initialize and Fetch the Smart Contracts:
Find the comment
// Step B - Effect hook to initialize and fetch the smart contracts when the provider changes.
Replace the existing
useEffect
hook with this updated code:
useStakingContract.ts
// Step B - Effect hook to initialize and fetch the smart contracts when the provider changes
useEffect
(
(
)
=>
{
(
async
(
)
=>
{
// Fetch the MainChain Testnet Contract
const
mainChainContract
=
await
fetchContract
(
"AELF"
,
"JRmBduh4nXWi1aXgdUsj5gJrzeZb2LxmrAbf7W99faZSvoAaE"
)
;
setMainChainSmartContract
(
mainChainContract
as
IContract
)
;
// Fetch the dAppChain Testnet Contract
const
sideChainContract
=
await
fetchContract
(
"tDVW"
,
"ASh2Wt7nSEmYqnGxPPzp4pnVDU4uhj1XW9Se5VeZcX2UDdyjx"
)
;
setSideChainSmartContract
(
sideChainContract
as
IContract
)
;
}
)
(
)
;
}
,
[
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 for the main chain, side chain.
MainChain Contract
: Fetches the mainchain testnet contract and sets it in the state.
dAppChain Contract
: Fetches the dAppChain testnet contract and sets it in the state.
Write Functions for Staking Contract
Step 4. Locate the File:
Go to the
src/hooks/useStakingContract.ts
file.
Step 5. Fetch the Smart Contract:
Find the comment
//Step C - Function to fetch a smart contract based on the chain symbol and the contract address
Replace the existing
fetchContract
function with this updated code:
useStakingContract.ts
//Step C - Function to fetch a smart contract based on the chain symbol and the contract address
const
fetchContract
=
async
(
symbol
:
"AELF"
|
"tDVW"
,
contractAddress
:
string
)
=>
{
try
{
// If no provider is available, return null
if
(
!
provider
)
return
null
;
// Fetch the chain information using the provider
const
chain
=
await
provider
.
getChain
(
symbol
)
;
if
(
!
chain
)
throw
new
Error
(
"Chain not found"
)
;
// Get the smart contract instance from the chain
const
contract
=
chain
.
getContract
(
contractAddress
)
;
// Return the smart contract instance
return
contract
;
}
catch
(
error
)
{
console
.
error
(
"Error in fetchContract"
,
{
symbol
,
contractAddress
,
error
}
)
;
}
}
;
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.
Step 6. Initialize and Fetch the Smart Contracts:
Find the comment
// Step D - Effect hook to initialize and fetch the smart contracts when the provider changes
Replace the existing
useEffect
hook with this updated code:
useStakingContract.ts
// Step D - Effect hook to initialize and fetch the smart contracts when the provider changes
useEffect
(
(
)
=>
{
(
async
(
)
=>
{
// Fetch the Staking Testnet Contract
const
stakingContract
=
await
fetchContract
(
"tDVW"
,
stakingContractAddress
)
;
setStakingSmartContract
(
stakingContract
as
IContract
)
;
}
)
(
)
;
}
,
[
provider
]
)
;
// Dependency array ensures this runs when the provider changes
Explanation:
useEffect
Hook
: This hook initializes and fetches the staking smart contract when the provider changes.
Check Provider
: If no provider is available, the function returns null.
Fetch Contracts
: It fetches and sets the smart contract for the staking.
By following these steps, we'll configure the Portkey provider to connect users' wallets to the dApp and interact with the multi-token and staking smart contract including interaction with the fungible token and the staking functionalities. This setup will enable our frontend components to perform actions like
create tokens
,
transfer tokens
, and
stake tokens
,
withdraw tokens
,
emergency withdraw tokens
, 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 Staking dApp. It allows users to connect their Portkey wallet with the staking dApp.
Before users can interact with the smart contract, we need to write the
Connect Wallet
function.
Find the comment
// Step E - Connect Portkey Wallet
.
Replace the existing connect function with this code snippet:
header/index.tsx
// Step E - Connect Portkey Wallet
const
connect
=
async
(
walletProvider
?
:
IPortkeyProvider
)
=>
{
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.
Update Connection Status
: Updates the state to indicate that the wallet is connected.
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
ConnectWallet
function defined, we're ready to write the remaining functions in the next steps.
Configure Create TOKEN Form
Step 1: Locate the File
Go to the
src/components/create-token-modal/index.tsx
file. This file is the
Create Fungible TOKEN
popup modal where users can create a new TOKEN by submitting the details like
tokenName
,
symbol
and
totalSupply
.
Step 2: Prepare Form to Create TOKEN
Find the comment
// Step F - Configure TOKEN Create Form
.
Replace the form variable with this code snippet:
create-token-modal/index.tsx
// Step F - Configure TOKEN Create Form
const
form
=
useForm
<
z
.
infer
<
typeof
formSchema
>>
(
{
resolver
:
zodResolver
(
formSchema
)
,
defaultValues
:
{
tokenName
:
"$T프로젝트로 돌아가기