Entenda como funciona o staking e como criar um contrato inteligente para staking de tokens.
Hoje estamos ouvindo muitas palavras novas no mundo Blockchain e staking é uma delas. As pessoas usam o conceito de staking geralmente para engajamento. Hoje vamos entender os pontos abaixo sobre staking.
- O que é Staking?
- Como escrever um contrato inteligente para staking de tokens?
- Como funciona o Processo de Staking?
- Implantação na rede de teste Rinkeby.
O que é Staking?
- Staking é uma forma de ganhar uma renda passiva extra por juros em sua criptomoeda, depositando-a por um período fixo ou dinâmico.
- Atualmente, algumas empresas utilizam o termo staking para engajamento.
- Nele, você coloca seu token ou NFT em stake e em troca recebe uma recompensa (depende do tempo que você deixou em stake).
Como Escrever um Contrato Inteligente para Staking de Tokens?
Observe as etapas abaixo:
- Criamos o Token ERC-20 Apple (APL) de exemplo.
- Ofereceremos fazer o stake do token por 3 meses (você pode mantê-lo por quanto tempo quiser).
- Após 3 meses, você receberá a recompensa de 32% do token que estava em stake. Exemplo: Se você colocar 100 tokens em stake, após 3 meses você receberá 132 tokens no total.
Processo do Contrato de Staking
- Primeiro, transferimos alguns tokens APL para o endereço do contrato de staking.
- Chamamos o método
approve
no contrato ERC20 com dois parâmetros. O primeiro endereço do contrato de staking e o segundo é o montante (aqui nós damos 50% do fornecimento total). - Chamamos o método
stakeToken
no contrato de Staking com o parâmetro de montante (Montante que você deseja fazer stake). - Após o término do período de staking, você pode chamar o método
claimReward
no contrato de staking e receberá seu montante com juros.
Aqui estão os passos para fazer isso acontecer no mundo blockchain.
- Criar o token ERC-20 APPLE (APL)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract AppleToken is ERC20 {
uint8 constant _decimals = 18;
uint256 constant _totalSupply = 100 * (10**6) * 10**_decimals; // 100 milhões de tokens para distribuição
constructor() ERC20("Apple", "APL") {
_mint(msg.sender, _totalSupply);
}
}
- Vamos criar um contrato StakeAPL com os dois métodos importantes
- Método stakeToken
- Método ClaimReward
- Método
StakeToken
: O usuário passa o montante em um parâmetro (está no formato Wei). Este método verifica todas as condições válidas, então transfere o montante em stake para um contrato e armazena esta entrada na estrutura e emite o evento Staked.
require(stakeAmount >0, "O montante em stake deve estar correto");
require(block.timestamp < planExpired , "Plano Expirado");
require(addressStaked[_msgSender()] == false, "Você já participou");
require(aplToken.balanceOf(_msgSender()) >= stakeAmount, "Saldo insuficiente");
aplToken.transferFrom(_msgSender(), address(this), stakeAmount);
stakeInfos[_msgSender()] = StakeInfo({
startTS: block.timestamp,
endTS: block.timestamp + planDuration,
amount: stakeAmount,
claimed: 0 });
emit Staked(_msgSender(), stakeAmount);
- Método
claimReward
: O usuário recebe a recompensa após o término da duração do staking. Primeiro, obtemos o montante que o usuário colocou em stake e, em seguida, calculamos a porcentagem de juros e o somamos. Transfira este montante para o endereço do usuário e emita o eventoClaimed
.
uint256 stakeAmount = stakeInfos[_msgSender()].amount;
uint256 totalTokens = stakeAmount + (stakeAmount * interestRate / 100);
stakeInfos[_msgSender()].claimed == totalTokens;
aplToken.transfer(_msgSender(), totalTokens);
emit Claimed(_msgSender(), totalTokens);
Como funciona o processo de Staking?
- Já temos um contrato ERC-20 (Token APL) e esse endereço de contrato passa para o tempo de implantação do construtor (constructor) StakeAPL.
- Transfira alguns tokens APL para o contrato
StakeAPL
. - O segundo usuário (que possui o token APL) chama o método approve do APL Token e dá a aprovação para o endereço do contrato de Staking com o valor do staking.
- Chame o método
stakeToken
do contrato de Staking com o montante como parâmetro e pronto. Depois de amadurecer o tempo de staking, você pode chamar o métodoclaimReward
. Você receberá o montante com juros.
Implantação na Rede de Teste Rinkeby
- Você pode copiar o código abaixo e implantar usando o Remix. você pode seguir este artigo para entender o Remix.
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.11;
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Context.sol";
interface Token {
function transfer(address recipient, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
function transferFrom(address sender, address recipient, uint256 amount) external returns (uint256);
}
contract StakeAPL is Pausable, Ownable, ReentrancyGuard {
Token aplToken;
// 30 Dias (30 * 24 * 60 * 60)
uint256 public planDuration = 2592000;
// 180 Dias (180 * 24 * 60 * 60)
uint256 _planExpired = 15552000;
uint8 public interestRate = 32;
uint256 public planExpired;
uint8 public totalStakers;
struct StakeInfo {
uint256 startTS;
uint256 endTS;
uint256 amount;
uint256 claimed;
}
event Staked(address indexed from, uint256 amount);
event Claimed(address indexed from, uint256 amount);
mapping(address => StakeInfo) public stakeInfos;
mapping(address => bool) public addressStaked;
constructor(Token _tokenAddress) {
require(address(_tokenAddress) != address(0),"O endereco do Token nao pode ser 0");
aplToken = _tokenAddress;
planExpired = block.timestamp + _planExpired;
totalStakers = 0;
}
function transferToken(address to,uint256 amount) external onlyOwner{
require(aplToken.transfer(to, amount), "A transferencia do token falhou!");
}
function claimReward() external returns (bool){
require(addressStaked[_msgSender()] == true, "Voce nao esta participando");
require(stakeInfos[_msgSender()].endTS < block.timestamp, "O tempo de stake ainda nao terminou");
require(stakeInfos[_msgSender()].claimed == 0, "Ja reivindicado");
uint256 stakeAmount = stakeInfos[_msgSender()].amount;
uint256 totalTokens = stakeAmount + (stakeAmount * interestRate / 100);
stakeInfos[_msgSender()].claimed == totalTokens;
aplToken.transfer(_msgSender(), totalTokens);
emit Claimed(_msgSender(), totalTokens);
return true;
}
function getTokenExpiry() external view returns (uint256) {
require(addressStaked[_msgSender()] == true, "Voce nao esta participando");
return stakeInfos[_msgSender()].endTS;
}
function stakeToken(uint256 stakeAmount) external payable whenNotPaused {
require(stakeAmount >0, "O montante em stake deve estar correto");
require(block.timestamp < planExpired , "Plano Expirado");
require(addressStaked[_msgSender()] == false, "Voce ja participou");
require(aplToken.balanceOf(_msgSender()) >= stakeAmount, "Saldo Insuficiente");
aplToken.transferFrom(_msgSender(), address(this), stakeAmount);
totalStakers++;
addressStaked[_msgSender()] = true;
stakeInfos[_msgSender()] = StakeInfo({
startTS: block.timestamp,
endTS: block.timestamp + planDuration,
amount: stakeAmount,
claimed: 0
});
emit Staked(_msgSender(), stakeAmount);
}
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
}
Artigo escrito por Arnish Gupta e traduzido por Marcelo Panegali
Top comments (0)