¿Es posible generar ingresos pasivos en el tesoro de tu DAO? ¿O durante tu preventa de tokens, subasta o en cualquier proyecto donde tengas tokens ERC20 inactivos en un contrato? En esta guÃa, lanzaremos un contrato de staking que realiza préstamos en AAVE en segundo plano.
Vamos a lanzar este contrato en Scroll Sepolia, pero también te mostraré qué se debe hacer para lanzarlo en cualquier otra red donde esté desplegado AAVE.
Nota: Vamos a usar Remix y Etherscan para lanzar e interactuar con los contratos. También puedes usar este repo como alternativa que incluye comentarios de código, unit tests en foundry, y una github action.
Paso1: Lanza el contrato Aave Lender
Si no lo has hecho aún, necesitarás instalar una wallet como Metamask, conectar tu wallet a Scroll Sepolia, y obtener fondos desde un faucet.
Lanza el siguiente contrato en Remix pasando las direcciones aavePoolAddress
y stakedTokenAddress
como parámetros en el constructor, en Scroll Sepolia estas son:
-
aavePoolAddress
:0x48914C788295b5db23aF2b5F0B3BE775C4eA9440
-
stakedTokenAddress
:0x7984E363c38b590bB4CA35aEd5133Ef2c6619C40
, el DAI testnet en Scroll Sepolia
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
library DataTypes {
struct ReserveConfigurationMap {
uint256 data;
}
struct ReserveData {
ReserveConfigurationMap configuration;
uint128 liquidityIndex;
uint128 currentLiquidityRate;
uint128 variableBorrowIndex;
uint128 currentVariableBorrowRate;
uint128 currentStableBorrowRate;
uint40 lastUpdateTimestamp;
uint16 id;
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
address interestRateStrategyAddress;
uint128 accruedToTreasury;
uint128 unbacked;
uint128 isolationModeTotalDebt;
}
}
interface IPool {
function borrow(
address asset,
uint256 amount,
uint256 interestRateMode, // 1 for Stable, 2 for Variable
uint16 referralCode,
address onBehalfOf) external;
function supply(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode) external;
function withdraw(
address asset,
uint256 amount,
address to) external returns (uint256);
function getReserveData(
address asset) external view returns (DataTypes.ReserveData memory);
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
contract AaveLender {
address public immutable AAVE_POOL_ADDRESS;
address public immutable STAKED_TOKEN_ADDRESS;
address public immutable ATOKEN_ADDRESS;
address public immutable OWNER;
mapping(address account => uint amount) public stakeByAccount;
uint public totalStake;
constructor(address aavePoolAddress, address stakedTokenAddress) {
AAVE_POOL_ADDRESS = aavePoolAddress;
STAKED_TOKEN_ADDRESS = stakedTokenAddress;
OWNER = msg.sender;
ATOKEN_ADDRESS = IPool(aavePoolAddress).getReserveData(stakedTokenAddress).aTokenAddress;
}
function stake(uint amount) public {
totalStake += amount;
stakeByAccount[msg.sender] += amount;
IERC20(STAKED_TOKEN_ADDRESS).transferFrom(msg.sender, address(this), amount);
IERC20(STAKED_TOKEN_ADDRESS).approve(AAVE_POOL_ADDRESS, amount);
IPool(AAVE_POOL_ADDRESS).supply(
STAKED_TOKEN_ADDRESS,
amount,
address(this),
0);
}
function unstake(uint amount) public {
require(amount <= stakeByAccount[msg.sender], "Not enough stake");
totalStake -= amount;
stakeByAccount[msg.sender] -= amount;
IPool(AAVE_POOL_ADDRESS).withdraw(
STAKED_TOKEN_ADDRESS,
amount,
msg.sender
);
}
function yieldEarned() public view returns(uint){
return IERC20(ATOKEN_ADDRESS).balanceOf(address(this)) - totalStake;
}
function withdraw(uint amount) public {
require(msg.sender == OWNER, "Sender is not owner");
require(amount <= yieldEarned(), "Maximum withdraw exceeded");
IPool(AAVE_POOL_ADDRESS).withdraw(
STAKED_TOKEN_ADDRESS,
amount,
msg.sender
);
}
}
Paso 2: Mintea DAI en testnet
DirÃgete ahora al Faucet de Aave y conecta tu wallet desde Scroll Sepolia. Haz click en el botón Faucet de DAI y confirma la transacción.
Una vez confirmada la transacción podrás ver en tu wallet tus DAIs en testnet si agregas su address de token 0x7984E363c38b590bB4CA35aEd5133Ef2c6619C40
.
Recuerda que no puedes hacer borrow y lending de cualquier token en Aave, únicamente de los que el protocolo le haya dado soporte de antemano. Y también toma nota que esta versión de DAI testnet en Scroll Sepolia no es la misma que la oficial circulando en los demás protocolos de Sepolia y Scroll Sepolia como Uniswap v3. Esta es una versión especial deployada por Aave y es la única versión compatible con Aave en el Testnet de Scroll. Si estás en cualquier red en mainnet sà deberás usar la versión oficial del token.
Paso 3: Aprueba el contrato de Aave Lending
Necesitamos aprobar el contrato de staking que recién lanzamos para que pueda acceder a los fondos.
Esto lo vamos a hacer en el Scroll-Etherscan.
En el contrato de DAI en: 0x7984E363c38b590bB4CA35aEd5133Ef2c6619C40
, conecta tu wallet y pasa los siguientes parámetros en la función approve
.
-
spender
: El address del contrato de staking que recién lanzamos -
amount
:100000000000000000000
que es 100 DAI en el formato wei.
Paso 4: Obtener ganancias
Ahora puedes stakear llamando la función stake
y pasando como párametro la cantidad de DAI que aprobaste.
En cada bloque, las ganancias (el yield) irán aumentando poco a poco. Las puedes observar llamando la función yieldEarned
. Las ganancias pueden ser enviadas al owner llamando la función withdraw
.
Próximos pasos
Este tutorial muestra cómo prestar en AAVE desde un smart contract con el código mÃnimo necesario. Ahora depende de ti utilizarlo para mejorar un proyecto existente o crear algo nuevo. Personalmente, me gustarÃa agregar este contrato a un sistema de loterÃa en el que estoy trabajando, donde mientras se elige el ganador el contrato deposita todas las recaudaciones en Aave. Déjame saber en los comentarios si tienes ideas o preguntas sobre este tutorial.
Conoce más sobre Aave desde la documentación oficial.
¡Gracias por ver este tutorial!
SÃgueme en dev.to y en Youtube para todo lo relacionado al desarrollo en Blockchain en Español.
Top comments (2)
Lo revierte la operación enviando el siguiente error :
[block:4401995 txIndex:6]from: 0xF26...16A31to: AaveLender.(constructor)value: 100 weidata: 0x610...19c40logs: 0hash: 0xfef...1ef10
Ante de eso cuando se hace la firma en el metamask envia la siguiente alerta :
Gas estimation failed
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
Returned error: {"jsonrpc":"2.0","error":"execution reverted","id":3115197577395175}
Hola amigo, un poco tarde en responder pero quizás te ayude a debuggear este video que hice sobre este artÃculo
youtube.com/watch?v=6GCktUAPbkk