bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 41쪽 중 29쪽
ate Token
Button.
You will get a transaction request on your Portkey wallet. Proceed to
Sign
the transaction.
After transaction is succesfully signed, you will get a successful/failed transaction notification.
Now, the transaction will be validated on the aelf blockchain. Let's wait till the transaction gets validated.
Once the transaction is successfully validated, a new
Sign
transaction request will pop-up on Portkey to
Create Token on the dAppChain
.
Click on the
Approve
button and wait for the transaction to complete.
After the successful creation of the token on the dAppChain, a new
Sign
transaction request will pop-up on Portkey to
Issue Tokens On the dAppChain
.
Click on the
Approve
button and wait for the transaction to complete.
Once tokens are issued successfully on the dAppChain, a new
Sign
transaction request will pop-up on Portkey to
Transfer Tokens to the Staking Contract
to distribute future staking rewards.
Click on the
Approve
button and wait for the transaction to complete.
Once the reward tokens are transferred successfully, a new
Sign
transaction request will pop-up on Portkey to
Initialize the Staking Contract
.
Click on the
Approve
button and wait for the transaction to complete.
Once the transaction is suceessfully completed, a notification will pop-up and the
Token balance
will be visible on the staking widget like below.
Stake Tokens
Enter the amount to stake the tokens and click on the
Stake $TOKEN
Button.
A new
Sign
transaction request will pop-up on Portkey to
Transfer $TOKEN amount to the staking contract
. Click on the
Sign
Button.
Now You will get another transaction request to
Deposit $TOKEN on the staking contract
on the Portkey Wallet. Click on the
Sign
Button.
A notification will pop-up that the
$TOKEN are Staked Succesfully
. The
Token balance
will be updated.
As we have completed all the necessary steps to stake the token, now it's time to withdraw the tokens.
There are two ways to withdraw the staked amount.
Emergency Withdraw Token
: User can withdraw staked tokens at anytime before the staking (lock) time period ends.
Withdraw Token
: User can withdraw staked tokens once the lock time period is over.
Let's do
Emergency Withdraw Token
in the next step.
Emergency Withdraw Tokens
After clicking on the staked token, A staked token entry will be visible on the
Staked $TOKEN
section like below.
Click on
Emergency Withdraw
Button.
Now, a transaction request will pop-up on the Portkey wallet.
The staked amount will be returned without any rewards and the token balance will be updated.
As we have completed
Emergency Withdraw Tokens
functioanlity. It's time to try
Withdraw Token
functionality.
Withdraw Token
First, the connected wallet needs to stake the tokens on the staking contract as we have already completed this during
Stake Tokens
step.
You need to wait till the lock time period is over for the staked amount.
After the lock period is over, you will be able to see your staked amount in
Available to Withdraw $TOKEN
section as shown below.
Click on
Withdraw
button to withdraw the amount including staking
Rewards
. 1.1 times the amount of the staked tokens.
Now, You will get the transaction request on the Portkey wallet to withdraw the staked amount.
Click on the
Sign
button.
Your staked tokens including rewards will be transferred to the connected wallet once the withdrawal request completes.
success
🎉 Congratulations Learners! You have successfully built your Staking dApp!
🎯 Conclusion
🎊 Congratulations on setting up your development environment and interacting with both the multi-token and staking smart contracts! 🎊 You've now built a solid foundation for handling advanced token operations and staking functionalities on the aelf blockchain. 🌟
📚 What You've Learned
Throughout this section, you've gained vital skills in:
🛠️ Setting Up Your Development Environment
: You installed essential tools like the .NET SDK, aelf contract templates, and the aelf deploy tool to prepare for smart contract development.
📦 Installing Node.js, Yarn, and aelf-command
: These tools enable efficient interaction with the aelf blockchain, facilitating wallet creation and transaction management.
💡 Getting Token Seed
: You obtained a TOKEN seed from the testnet faucet, a fundamental step in creating fungible tokens.
🔧 Configuring Frontend Integration
: You set up a frontend that interacts with both the multi-token and staking contracts, enabling user-friendly functionality including functions like token creation, token issuance, stake tokens, and withdraw tokens in your dApp.
🔍 Final Output
By now, you should have:
📜 Successfully set up your development environment and installed all required packages.
💻 Configured your frontend to interact with both the multi-token and staking smart contracts, enabling functionalities like creating tokens, issuing them on the dAppChain, staking, and withdrawing tokens.
➡️ What's Next?
With a comprehensive understanding of token creation, staking, and contract interaction, you're prepared to explore further aspects of blockchain development. Consider diving into:
📊 Advanced Smart Contract Logic
: Add more complex features and security to your contracts.
Enhanced Staking Protocols
: Learn about advanced staking mechanisms and rewards structures to elevate your dApp.
🌐 Cross-Chain Interoperability
: Explore how aelf’s cross-chain capabilities enable seamless communication between different blockchains.
Keep experimenting and innovating with aelf! Your journey into decentralized finance and blockchain development is just getting started. 🚀
Happy coding and building on the aelf blockchain! 😊
Step 1 - Setting up your development environment
Step 2 - Develop Smart Contract
Start Your Smart Contract Project
Adding Your Smart Contract Code
Building Smart Contract
Step 3 - Deploy Smart Contract
Step 4 - Getting TOKEN Seed
Step 5 - Interact with Your Deployed Smart Contracts
Project Setup
Configure Portkey Provider & Write Contract Hooks Function
Configure Connect Wallet Function
Configure Create TOKEN Form
Get CrossChain Contract
Get the parent chain height
Fetch the Merkle path
Get Token Contract
Create Fungible Token on the MainChain
Create Fungible Token on dAppChain
Issue the created token on the dAppChain
Transfer Token to Staking Contract
Initialize the staking contract
Configure Submit Form
Fetch Token Data
Deposit Stake Amount on the Staking Contract
Fetch Deposited (Staked) Tokens
Fetch Total Staked Amount
Withdraw Staked Tokens
Emergency Withdraw Staked Tokens
Set Staking Contract Address
Run Application
🎯 Conclusion
## /quick-start/developers/dice-game-dapp
On this page
Description
: This contract is moderately complex. It demonstrates the use of
state variables, user interactions, and random number generation using Aetherlink VRF to create a dice game where users can bet on the outcome of the dice roll. Aetherlink is a decentralized oracle network on aelf blockchain.
Purpose
: To introduce you to more advanced concepts such as state management, event handling, and randomization using oracle networks in smart contracts.
Difficulty Level
: Moderate
Step 1 - Setting up your development environment
Local
Codespaces
Basic knowledge of terminal commands
IDE
- Install
VS Code
Note for Apple Silicon users:
Ensure that Rosetta is installed, if it is not, use the following command:
Terminal
softwareupdate --install-rosetta
Install Required Packages
Install dotnet 8.0.x SDK
Install aelf contract templates
Linux and macOs
Windows
Terminal
dotnet new
--install
AElf.ContractTemplates
Command Prompt
dotnet new
install
AElf.ContractTemplates
AELF.ContractTemplates contains various predefined templates for the ease of developing smart contracts on the aelf blockchain.
Install aelf deploy tool
Terminal
dotnet tool
install
--global
aelf.deploy
aelf.deploy is a utility tool for deploying smart contracts on the aelf blockchain.
Please remember to export PATH after installing aelf.deploy.
info
ℹ️ Note: If you have installed aelf.deploy and your terminal says that there is no such command available, please uninstall and install aelf.deploy.
Install Node.js and Yarn
Install Node.js
Install Yarn
Install aelf-command
Linux and macOs
Windows
Terminal
sudo
npm
i
-g
aelf-command
Command Prompt
npm
i
-g
aelf-command
aelf-command is a CLI tool for interacting with the aelf blockchain, enabling tasks like creating wallets and managing transactions.
Provide required permissions while installing aelf-command globally.
Visit
aelf-devcontainer-template
.
Click the
Use this template
button. Choose
Create a new repository
.
Enter a suitable repository name. Click
Create repository
.
Within the GitHub interface of your new repository, click on
Code
.
Select
Codespaces
.
Click on the
+
sign to create a new Codespace.
After some time, your workspace will load with the contents of the repository.
You can now continue your development using GitHub Codespaces.
Step 2 - Develop Smart Contract
Start Your Smart Contract Project
Open your
Terminal
.
Enter the following command to generate a new project:
Terminal
mkdir
dice-game
cd
dice-game
dotnet new aelf
-n
DiceGame
Adding Your Smart Contract Code
Now that we have a template dice game project, we can customise the template to incorporate our own contract logic.
Lets start by implementing methods to provide basic functionality for interacting with the oracle to generate a verifiable random number. Then updating and reading a message stored persistently in the contract state to determine outcome of the game.
Enter this command in your
Terminal
.
Terminal
cd
src
Defining Methods and Messages
Rename the file name from
Protobuf/contract/hello_world_contract.proto
to
dice_master_contract.proto
:
Terminal
mv
Protobuf/contract/hello_world_contract.proto Protobuf/contract/dice_master_contract.proto
open the project with your IDE.
The implementation of file
src/Protobuf/contract/dice_master_contract.proto
is as follows:
dice_master_contract.proto
syntax
=
"proto3"
;
import
"aelf/core.proto"
;
import
"aelf/options.proto"
;
import
"google/protobuf/empty.proto"
;
import
"google/protobuf/wrappers.proto"
;
import
"Protobuf/reference/acs12.proto"
;
import
"Protobuf/message/request_interface.proto"
;
// The namespace of this class
option
csharp_namespace
=
"AElf.Contracts.DiceMaster"
;
service
DiceMaster
{
// The name of the state class the smart contract is going to use to access blockchain state
option
(
aelf
.
csharp_state
)
=
"AElf.Contracts.DiceMaster.DiceMasterState"
;
option
(
aelf
.
base
)
=
"Protobuf/reference/acs12.proto"
;
option
(
aelf
.
base
)
=
"Protobuf/message/request_interface.proto"
;
rpc
Initialize
(
google
.
protobuf
.
Empty
)
returns
(
google
.
protobuf
.
Empty
)
{
}
rpc
Play
(
google
.
protobuf
.
Int64Value
)
returns
(
google
.
protobuf
.
Empty
)
{
}
rpc
Withdraw
(
google
.
protobuf
.
Int64Value
)
returns
(
google
.
protobuf
.
Empty
)
{
}
rpc
Deposit
(
google
.
protobuf
.
Int64Value
)
returns
(
google
.
protobuf
.
Empty
)
{
}
rpc
TransferOwnership
(
aelf
.
Address
)
returns
(
google
.
protobuf
.
Empty
)
{
}
rpc
SetSubscriptionId
(
google
.
protobuf
.
Int64Value
)
returns
(
google
.
protobuf
.
Empty
)
{
}
rpc
SetOracleNodeId
(
google
.
protobuf
.
Int32Value
)
returns
(
google
.
protobuf
.
Empty
)
{
}
rpc
GetPlayAmountLimit
(
google
.
protobuf
.
Empty
)
returns
(
PlayAmountLimitMessage
)
{
option
(
aelf
.
is_view
)
=
true
;
}
rpc
GetContractBalance
(
google
.
protobuf
.
Empty
)
returns
(
google
.
protobuf
.
Int64Value
)
{
option
(
aelf
.
is_view
)
=
true
;
}
rpc
GetOwner
(
google
.
protobuf
.
Empty
)
returns
(
google
.
protobuf
.
StringValue
)
{
option
(
aelf
.
is_view
)
=
true
;
}
rpc
GetSubscriptionId
(
google
.
protobuf
.
Empty
)
returns
(
google
.
protobuf
.
Int64Value
)
{
option
(
aelf
.
is_view
)
=
true
;
}
rpc
GetOracleNodeId
(
google
.
protobuf
.
Empty
)
returns
(
google
.
protobuf
.
Int32Value
)
{
option
(
aelf
.
is_view
)
=
true
;
}
rpc
GetPlayerInfo
(
aelf
.
Address
)
returns
(
PlayerInfo
)
{
option
(
aelf
.
is_view
)
=
true
;
}
}
// An event that will be emitted from contract method call when Play is called.
message
PlayOutcomeEvent
{
option
(
aelf
.
is_event
)
=
true
;
int64
amount
=
1
;
int64
won
=
2
;
aelf
.
Address
from
=
3
;
}
// An event that will be emitted from contract method call when Withdraw is called.
message
WithdrawEvent
{
option
(
aelf
.
is_event
)
=
true
;
int64
amount
=
1
;
aelf
.
Address
from
=
2
;
aelf
.
Address
to
=
3
;
}
// An event that will be emitted from contract method call when Deposit is called.
message
DepositEvent
{
option
(
aelf
.
is_event
)
=
true
;
int64
amount
=
1
;
aelf
.
Address
from
=
2
;
aelf
.
Address
to
=
3
;
}
// The message containing the play amount limits
message
PlayAmountLimitMessage
{
int64
minimumAmount
=
1
;
int64
maximumAmount
=
2
;
}
message
PlayedRecord
{
aelf
.
Address
address
=
1
;
int64
blockNumber
=
2
;
}
message
PlayerInfo
{
aelf
.
Address
address
=
1
;
int64
dice1
=
2
;
int64
dice2
=
3
;
bool
win
=
4
;
int64
amount
=
5
;
bool
pending
=
6
;
int64
blockNumber
=
7
;
}
Define Contract States
The implementation of file
src/DiceMasterState.cs
is as follows:
src/DiceMasterState.cs
using
AElf
.
Sdk
.
CSharp
.
State
;
using
AElf
.
Types
;
namespace
AElf
.
Contracts
.
DiceMaster
{
// The state class is access the blockchain state
public
partial
class
DiceMasterState
:
ContractState
{
// A state to check if contract is initialized
public
BoolState
Initialized
{
get
;
set
;
}
// A state to store the owner address
public
SingletonState
<
Address
>
Owner
{
get
;
set
;
}
public
MappedState
<
Hash
,
PlayedRecord
>
PlayedRecords
{
get
;
set
;
}
public
SingletonState
<
int
>
OracleNodeId
{
get
;
set
;
}
public
SingletonState
<
long
>
SubscriptionId
{
get
;
set
;
}
public
MappedState
<
Address
,
PlayerInfo
>
PlayerInfos
{
get
;
set
;
}
}
}
Token Contract Reference State
Create a new file
token_contract.proto
under
src/Protobuf/reference/
.
Replace this code of implementation file of
token_contract.proto
:
token_contract.proto
/**
* MultiToken contract.
*/
syntax
=
"proto3"
;
package
token
;
import
"aelf/core.proto"
;
import
"aelf/options.proto"
;
import
"google/protobuf/empty.proto"
;
import
"google/protobuf/wrappers.proto"
;
option
csharp_namespace
=
"AElf.Contracts.MultiToken"
;
service
TokenContract
{
// Create a new token.
rpc
Create
(
CreateInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Issuing some amount of tokens to an address is the action of increasing that addresses balance
// for the given token. The total amount of issued tokens must not exceed the total supply of the token
// and only the issuer (creator) of the token can issue tokens.
// Issuing tokens effectively increases the circulating supply.
rpc
Issue
(
IssueInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Transferring tokens simply is the action of transferring a given amount of tokens from one address to another.
// The origin or source address is the signer of the transaction.
// The balance of the sender must be higher than the amount that is transferred.
rpc
Transfer
(
TransferInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// The TransferFrom action will transfer a specified amount of tokens from one address to another.
// For this operation to succeed the from address needs to have approved (see allowances) enough tokens
// to Sender of this transaction. If successful the amount will be removed from the allowance.
rpc
TransferFrom
(
TransferFromInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// The approve action increases the allowance from the Sender to the Spender address,
// enabling the Spender to call TransferFrom.
rpc
Approve
(
ApproveInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
rpc
BatchApprove
(
BatchApproveInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// This is the reverse operation for Approve, it will decrease the allowance.
rpc
UnApprove
(
UnApproveInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// This method can be used to lock tokens.
rpc
Lock
(
LockInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// This is the reverse operation of locking, it un-locks some previously locked tokens.
rpc
Unlock
(
UnlockInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// This action will burn the specified amount of tokens, removing them from the token’s Supply.
rpc
Burn
(
BurnInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Set the primary token of side chain.
rpc
SetPrimaryTokenSymbol
(
SetPrimaryTokenSymbolInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// This interface is used for cross-chain transfer.
rpc
CrossChainTransfer
(
CrossChainTransferInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// This method is used to receive cross-chain transfers.
rpc
CrossChainReceiveToken
(
CrossChainReceiveTokenInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// The side chain creates tokens.
rpc
CrossChainCreateToken
(
CrossChainCreateTokenInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// When the side chain is started, the side chain is initialized with the parent chain information.
rpc
InitializeFromParentChain
(
InitializeFromParentChainInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Handle the transaction fees charged by ChargeTransactionFees.
rpc
ClaimTransactionFees
(
TotalTransactionFeesMap
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Used to collect transaction fees.
rpc
ChargeTransactionFees
(
ChargeTransactionFeesInput
)
returns
(
ChargeTransactionFeesOutput
)
{
}
rpc
ChargeUserContractTransactionFees
(
ChargeTransactionFeesInput
)
returns
(
ChargeTransactionFeesOutput
)
{
}
// Check the token threshold.
rpc
CheckThreshold
(
CheckThresholdInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Initialize coefficients of every type of tokens supporting charging fee.
rpc
InitialCoefficients
(
google
.
protobuf
.
Empty
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Processing resource token received.
rpc
DonateResourceToken
(
TotalResourceTokensMaps
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// A transaction resource fee is charged to implement the ACS8 standards.
rpc
ChargeResourceToken
(
ChargeResourceTokenInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Verify that the resource token are sufficient.
rpc
CheckResourceToken
(
google
.
protobuf
.
Empty
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Set the list of tokens to pay transaction fees.
rpc
SetSymbolsToPayTxSizeFee
(
SymbolListToPayTxSizeFee
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Update the coefficient of the transaction fee calculation formula.
rpc
UpdateCoefficientsForSender
(
UpdateCoefficientsInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// Update the coefficient of the transaction fee calculation formula.
rpc
UpdateCoefficientsForContract
(
UpdateCoefficientsInput
)
returns
(
google
.
protobuf
.
Empty
)
{
}
// This method is used to initialize the governance organization for some functions,
// including: the coefficient of the user transaction fee calculation formula,
// the coefficient of the contract developer resource fee calculation formula, and the side chain rental fee.
rpc
InitializeAuthorizedController
(
google
.
protobuf
.
Empty
)
returns
(
google
.
protobuf
.
Empty
)
{
}
rpc
AddAddressToCreateTokenWhiteList
(
aelf
.
Address
)
returns
(
google
.
pr프로젝트로 돌아가기