@glue-finance/expansions-pack
Version:
Glue Protocol Expansions Pack - Smart contract interfaces and base contracts for building with the Glue Protocol
784 lines (598 loc) โข 32.4 kB
Markdown
# Glue Protocol Expansions Pack
[](https://badge.fury.io/js/@glue-finance/expansions-pack)
[](https://github.com/glue-finance/glue-expansionspack/blob/main/LICENSE)
**Expand the Glue Protocol with pre-built, battle-tested smart contracts designed for rapid development.**
## What is the Glue Expansions Pack?
The Glue Expansions Pack provides **ready-to-use smart contract components** that allow developers to build on top of the Glue Protocol without needing to understand all the complex underlying interactions. Instead of implementing protocol-specific logic from scratch, builders can focus entirely on their unique business logic while leveraging the power of the Glue ecosystem.
### ๐ฏ **Main Use Cases**
The Expansions Pack is built around **two primary expansion patterns**:
#### 1. **StickyAsset** - Create Your Own Sticky Tokens
Transform any token (ERC20, ERC721, or custom) into a **sticky asset** backed by collateral from the Glue Protocol. Perfect for:
- **Native Glue integration** with automatic protocol compatibility
- **Hook implementations** for custom logic during ungluing operations
- **Collateral-backed tokens** using Glue's native backing system
- **Protocol fee handling** with automatic distribution mechanisms
- **Multi-interface support** for both ERC20 and ERC721 sticky assets
#### 2. **GluedLoanReceiver** - Access Instant Liquidity
Build applications that leverage **flash loans** from the Glue Protocol with automatic repayment handling. Ideal for:
- **Glue Protocol flash loans** with type-safe interface integration
- **Automatic repayment handling** built into the base contract
- **Cross-glue liquidity** aggregation for larger loan amounts
- **Protocol-native fee calculations** with built-in fee handling
- **Multi-glue support** for both ERC20 and ERC721 glue contracts
### ๐ก **Why Use the Expansions Pack?**
**Focus on Your Innovation, Not Protocol Complexity:**
- โ
**Pre-built integrations** - No need to understand Glue's internal mechanics
- โ
**Battle-tested code** - Production-ready contracts with comprehensive testing
- โ
**Automatic protocol handling** - Fees, hooks, and edge cases handled automatically
- โ
**Plug-and-play design** - Import, inherit, and customize for your needs
- โ
**Comprehensive documentation** - Examples and guides for every use case
## Overview
The Glue Expansions Pack includes essential interfaces, base contracts, libraries, and testing utilities for rapid Glue Protocol integration:
- **Base Contracts**: `StickyAsset`, `GluedLoanReceiver` - Core building blocks for protocol expansion
- **Interfaces**: `IGlueERC20`, `IGlueERC721`, `IStickyAsset`, `IGluedLoanReceiver` - Standard protocol interfaces
- **Libraries**: `GluedMath` - High-precision mathematical operations and decimal conversions
- **Examples**: Ready-to-deploy implementations for common use cases
- **Testing Mocks**: Comprehensive testing framework with accurate protocol simulation
## Installation
```bash
npm install -finance/expansions-pack
```
## Usage
Once installed, you can import and use the base contracts in your Solidity files. The two main expansion patterns are:
### 1. Creating Sticky Assets with StickyAsset
Inherit from `StickyAsset` to transform any token into a sticky asset backed by the Glue Protocol:
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import "@glue-finance/expansions-pack/base/StickyAsset.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20, StickyAsset {
constructor()
ERC20("My Sticky Token", "MST")
StickyAsset(
"https://example.com/metadata.json", // EIP-7572 contract URI
[true, false] // [FUNGIBLE: true (ERC20), HOOK: false (no hooks)]
)
{
_mint(msg.sender, 1000000 * 10**18);
// Your token now automatically integrates with Glue Protocol!
}
// Optional: Override hook functions for custom behavior
function _calculateStickyHookSize(uint256 amount) internal view override returns (uint256) {
// Custom logic for sticky asset hooks
return 0; // No hooks by default
}
function _processStickyHook(uint256 amount, uint256[] memory tokenIds) internal override {
// Custom logic when hooks are executed
// Example: burn tokens, distribute to treasury, etc.
}
}
```
### 2. Building Flash Loan Applications with GluedLoanReceiver
Inherit from `GluedLoanReceiver` to build applications that leverage instant liquidity:
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import "@glue-finance/expansions-pack/base/GluedLoanReceiver.sol";
contract MyArbitrageBot is GluedLoanReceiver {
// Implement your core business logic here
function _executeFlashLoanLogic(bytes memory params) internal override returns (bool success) {
// Access loan information
uint256 totalBorrowed = this.getCurrentTotalBorrowed();
address collateral = this.getCurrentCollateral();
// Decode your custom parameters
(address targetDEX, uint256 minProfit) = abi.decode(params, (address, uint256));
// Your arbitrage/MEV/liquidation logic here
uint256 profit = _executeYourStrategy(collateral, totalBorrowed, targetDEX);
// Return true if successful (repayment is automatic)
return profit >= minProfit;
}
function _executeYourStrategy(address token, uint256 amount, address dex) internal returns (uint256 profit) {
// Your custom strategy implementation
// Buy low, sell high, liquidate positions, etc.
return 0; // Return actual profit
}
// Public function to initiate flash loans
function executeStrategy(
address stickyAsset,
address collateral,
uint256 amount,
address targetDEX,
uint256 minProfit
) external {
bytes memory params = abi.encode(targetDEX, minProfit);
_requestFlashLoan(stickyAsset, collateral, amount, params);
}
}
```
### 3. Using Protocol Interfaces
Import standard interfaces for type-safe interactions with the Glue Protocol:
```solidity
import "@glue-finance/expansions-pack/interfaces/IGlueERC20.sol";
import "@glue-finance/expansions-pack/interfaces/IGlueERC721.sol";
import "@glue-finance/expansions-pack/interfaces/IStickyAsset.sol";
contract MyDApp {
function interactWithGlue(address glueContract, address collateral, uint256 amount) external {
// Type-safe interaction with any Glue contract
IGlueERC20(glueContract).unglue([collateral], amount, msg.sender);
}
}
```
### 4. High-Precision Math Operations
Use the GluedMath library for accurate calculations:
```solidity
import "@glue-finance/expansions-pack/libraries/GluedMath.sol";
contract MyContract {
using GluedMath for uint256;
function calculatePreciseAmount(uint256 a, uint256 b, uint256 denominator) public pure returns (uint256) {
return GluedMath.md512(a, b, denominator);
}
function adjustTokenDecimals(uint256 amount, address tokenIn, address tokenOut) public view returns (uint256) {
return GluedMath.adjustDecimals(amount, tokenIn, tokenOut);
}
}
```
## GluedMath Library - High-Precision Calculations
The `GluedMath` library provides **ultra-precise mathematical operations** and **automatic decimal adjustments** essential for DeFi applications. It handles the complex math needed for cross-token calculations, fee computations, and proportion calculations.
### Key Functions
#### 1. **High-Precision Multiplication and Division (`md512`)**
Performs multiplication and division with 512-bit intermediate precision to prevent overflow and maintain accuracy:
```solidity
import "@glue-finance/expansions-pack/libraries/GluedMath.sol";
contract PrecisionExample {
using GluedMath for uint256;
uint256 constant PRECISION = 1e18;
function calculateFee(uint256 amount, uint256 feeRate) public pure returns (uint256) {
// Calculate 2.5% fee with perfect precision
// feeRate = 25e15 (2.5% in 1e18 precision)
return GluedMath.md512(amount, feeRate, PRECISION);
}
function calculateProportion(uint256 userAmount, uint256 totalSupply, uint256 totalValue) public pure returns (uint256) {
// Calculate user's proportional share: (userAmount * totalValue) / totalSupply
return GluedMath.md512(userAmount, totalValue, totalSupply);
}
}
```
#### 2. **Automatic Decimal Adjustment (`adjustDecimals`)**
Automatically converts amounts between tokens with different decimal places:
```solidity
contract DecimalExample {
using GluedMath for uint256;
function convertTokenAmounts(uint256 amount, address fromToken, address toToken) public view returns (uint256) {
// Automatically handles USDC (6 decimals) โ WETH (18 decimals) conversions
return GluedMath.adjustDecimals(amount, fromToken, toToken);
}
function convertUSDCToWETH(uint256 usdcAmount) public view returns (uint256) {
// Convert 1000 USDC (1000 * 1e6) to WETH decimals (1000 * 1e18)
address USDC = 0xA0b86a33E6417c4e2fDF5F3A4EB59b6A3DFEd3B5;
address WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
return GluedMath.adjustDecimals(usdcAmount, USDC, WETH);
}
}
```
The Expansions Pack helps you build on top of Glue Protocol without needing to be an expert in its internal mechanics. As a bonus, **GluedMath** simplifies common mathematical challenges when working with different token decimals and precision calculations.
**Key Benefits:**
- **Prevents Overflow**: 512-bit intermediate calculations prevent overflow in large multiplications
- **Maintains Precision**: No rounding errors in critical financial calculations
- **Handles Decimals**: Automatic conversion between different token decimal formats
- **Gas Optimized**: Efficient assembly implementation for production use
- **Battle Tested**: Used throughout the Glue Protocol for all precision-critical operations
## Examples
The Expansions Pack includes **ready-to-deploy example contracts** for common use cases. These are complete implementations that you can deploy directly or use as starting points:
### Ready-to-Deploy Sticky Tokens
#### BasicStickyToken - Minimal Implementation
```solidity
import "@glue-finance/expansions-pack/examples/BasicStickyToken.sol";
// Deploy with minimal configuration
contract MyToken is BasicStickyToken {
constructor() BasicStickyToken(
[
"https://mytoken.com/metadata.json", // contractURI
"My Sticky Token", // name
"MST" // symbol
],
1000000 * 10**18 // initial supply
) {
// Ready to use! Your token is now backed by Glue Protocol
}
}
```
#### AdvancedStickyToken - Full-Featured Implementation
```solidity
import "@glue-finance/expansions-pack/examples/AdvancedStickyToken.sol";
// Deploy with full configuration including fees, governance, and limits
contract MyAdvancedToken is AdvancedStickyToken {
constructor() AdvancedStickyToken(
[
"https://mytoken.com/metadata.json",
"Advanced Token",
"ADV"
],
[
5e16, // maxOwnerFee (5%)
1e16, // ownerFee (1%)
0, // maxSupply (unlimited)
3, // feeSource (FROM_BOTH)
1000000 * 10**18 // initialSupply
],
[
msg.sender, // owner
msg.sender, // feeReceiver
address(0), // blacklist (none)
msg.sender // collateralManager
],
[
false, false, false, false, // locks for security
false, false, false, false
]
) {
// Full-featured token with governance, fees, and collateral management
}
}
```
### Ready-to-Deploy Flash Loan Applications
#### ExampleArbitrageBot - Complete MEV Bot
```solidity
import "@glue-finance/expansions-pack/examples/ExampleArbitrageBot.sol";
// Deploy a complete arbitrage bot
contract MyArbitrageBot is ExampleArbitrageBot {
constructor(address _owner) ExampleArbitrageBot(_owner) {
// Ready-to-use MEV bot with:
// - Multi-DEX arbitrage capabilities
// - Automatic profit calculation
// - Emergency controls and access management
// - Gas optimization and slippage protection
}
// Start arbitraging immediately!
function startArbitrage(
address stickyAsset,
address collateral,
uint256 amount,
address dexA,
address dexB
) external onlyOwner {
executeArbitrage(stickyAsset, collateral, amount, dexA, dexB);
}
}
```
### Custom Strategy Examples
#### Creating a Rebasing Token
```solidity
import "@glue-finance/expansions-pack/base/StickyAsset.sol";
contract RebasingToken is ERC20, StickyAsset {
constructor()
ERC20("Rebase Token", "REBASE")
StickyAsset("https://metadata.json", [true, true]) // Enable hooks
{
_mint(msg.sender, 1000000 * 10**18);
}
// Implement rebasing logic in hooks
function _processCollateralHook(address asset, uint256 amount, bool isETH) internal override {
// Automatically compound rewards into token supply
if (asset == rewardToken) {
_mint(address(this), amount); // Increase supply = rebasing!
}
}
}
```
#### Treasury-Funded Token
```solidity
import "@glue-finance/expansions-pack/base/StickyAsset.sol";
contract TreasuryToken is ERC20, StickyAsset {
address public treasury;
constructor(address _treasury)
ERC20("Treasury Token", "TREAS")
StickyAsset("https://metadata.json", [true, true])
{
treasury = _treasury;
_mint(msg.sender, 1000000 * 10**18);
}
function _calculateCollateralHookSize(address asset, uint256 amount) internal view override returns (uint256) {
return _md512(amount, 10e16, PRECISION); // 10% to treasury
}
function _processCollateralHook(address asset, uint256 amount, bool isETH) internal override {
// Automatically fund treasury from ungluing operations
if (isETH) {
payable(treasury).transfer(amount);
} else {
IERC20(asset).transfer(treasury, amount);
}
}
}
```
#### Simple Arbitrage Bot Implementation
```solidity
import "@glue-finance/expansions-pack/base/GluedLoanReceiver.sol";
contract ArbitrageBot is GluedLoanReceiver {
function _executeFlashLoanLogic(bytes memory params) internal override returns (bool success) {
// Use enhanced interface for comprehensive loan information
(
address[] memory glues,
address collateral,
uint256[] memory expectedAmounts,
uint256 totalBorrowed,
uint256 totalRepay,
uint256 totalFees
) = this.getCurrentLoanInfo();
// Execute arbitrage strategy
uint256 profit = _performArbitrage(collateral, totalBorrowed);
// Return true if profitable (repayment is automatic)
return profit > totalFees;
}
function _performArbitrage(address token, uint256 amount) internal returns (uint256 profit) {
// Your arbitrage logic here
// Buy low on DEX A, sell high on DEX B
return 0; // Return actual profit
}
}
```
## ๐งช Mock Contracts for Testing
The Glue Expansions Pack includes **simple mock contracts** designed for testing your integrations without deploying the full Glue Protocol. Each mock focuses on **one specific function** with **manual parameter control** and **realistic protocol behavior**.
### Hook Simulation
All mock contracts implement accurate hook behavior from the real Glue Protocol:
#### **For ERC20 Contracts (`MockUnglueERC20`, `MockBatchUnglueERC20`)**
- **Phase 1 - Sticky Asset Hooks**: Applied via `tryHook(stickyAsset, amount)` during initialization
- Reduces the effective amount used for proportion calculation
- Hook amount is transferred to sticky asset (simulated)
- Matches `GlueERC20.initialization() -> tryHook()` flow exactly
- **Phase 2 - Collateral Hooks**: Applied via `tryHook(collateral, netAmount)` during distribution
- Reduces the final amount received by user
- Hook amount is transferred to sticky asset (simulated)
- Matches `GlueERC20.computeCollateral() -> tryHook()` flow exactly
#### **For ERC721 Contracts (`MockUnglueERC721`, `MockBatchUnglueERC721`)**
- **Phase 1 - Sticky Asset Hooks (NFTs)**: Applied via `tryHook(stickyAsset, nftCount, tokenIds)`
- **Does NOT transfer** any amount to sticky asset (key difference!)
- **Still calls executeHook** with NFT count and actual tokenIds array
- **Returns 0** (no amount reduction)
- Used for **tracking burned NFT IDs** in expanded integrations
- **Phase 2 - Collateral Hooks (ERC20/ETH)**: Applied via `tryHook(collateral, netAmount, tokenIds)`
- Same as ERC20 behavior - transfers hook amount to sticky asset
- Calls executeHook with hookAmount and tokenIds
- Returns `netAmount - hookAmount`
#### **Real Protocol Matching Features**
- โ
**BIO State Management**: 0=UNCHECKED, 1=NO_HOOK, 2=HOOK (matches real protocol)
- โ
**Hook Interface Simulation**: `hasHook()`, `hookSize()`, `hooksImpact()`, `executeHook()`
- โ
**Proper Hook Discovery**: Simulates real protocol's hook detection process
- โ
**Accurate Transfers**: Hook amounts actually transferred to sticky asset (simulated)
- โ
**NFT ID Tracking**: Full tokenIds array passed to executeHook for NFT hooks
- โ
**Fee Calculations**: Real protocol fee math (0.1% protocol fee)
- โ
**Event Emissions**: Standard unglued events with correct parameters
### โ ๏ธ **Important: ERC20 vs ERC721 Interface Differences**
The Glue Protocol has different interfaces for ERC20 tokens and ERC721 NFTs. We provide **separate mock contracts** for each interface:
| Function | ERC20 Interface | ERC721 Interface |
|----------|-----------------|------------------|
| **Individual Unglue** | `unglue(collaterals[], amount, recipient)` | `unglue(collaterals[], tokenIds[], recipient)` |
| **Batch Unglue** | `batchUnglue(assets[], amounts[], collaterals[], recipients[])` | `batchUnglue(assets[], tokenIds[][], collaterals[], recipients[])` |
**Key Differences:**
- **ERC20**: Uses `uint256 amount` parameter for token amounts
- **ERC721**: Uses `uint256[] tokenIds` or `uint256[][]` arrays for NFT token IDs
- **Calculations**: ERC20 uses amount/totalSupply, ERC721 uses nftCount/totalSupply
- **Hook Behavior**: ERC20 hooks transfer amounts, NFT hooks only track (no transfers)
### Why Use These Mocks?
- โ
**Test without mainnet deployment**: No need for full protocol setup
- โ
**Complete control**: Manually set supply deltas, balances, fees
- โ
**Standard interfaces**: Use real IGlueERC20/IGlueERC721/IGlueStickERC20/IGlueStickERC721 interfaces
- โ
**Individual focus**: Each mock tests one specific function
- โ
**Comprehensive documentation**: Extensive examples and clear instructions
- โ
**Accurate behavior**: Real protocol fee calculations and hook simulation
- โ
**Hook testing**: Test hooks with proper two-phase simulation
- โ
**Real hook transfers**: Hook amounts actually transferred to sticky asset
### Available Mock Contracts
#### 1. MockUnglueERC20 - Test Individual ERC20 Unglue Operations
**Focus**: Testing `IGlueERC20.unglue(collaterals, amount, recipient)` functionality with accurate hook simulation.
```solidity
// Import and deploy
import "@glue-finance/expansions-pack/mocks/MockUnglueERC20.sol";
contract TestMyERC20Strategy {
MockUnglueERC20 mockGlue;
function setUp() public {
mockGlue = new MockUnglueERC20();
// Configure the mock
mockGlue.setStickyAsset(myERC20Token);
mockGlue.setMockTotalSupply(1000e18); // 1000 token total supply
// Add collateral
mockGlue.addCollateral(USDC, 1000e6); // 1000 USDC
mockGlue.addETH{value: 1e18}(); // 1 ETH
// Configure the mock hooks (matches real protocol)
mockGlue.configureHooks(true, 5e16); // 5% sticky asset hook
mockGlue.setAssetHookSize(USDC, 2e16); // 2% USDC hook
}
function testHookSimulation() public {
address[] memory collaterals = new address[](2);
collaterals[0] = USDC;
collaterals[1] = address(0); // ETH
// Execute unglue - burn 100 tokens
mockGlue.unglue(collaterals, 100e18, alice);
// PHASE 1: tryHook(myERC20Token, 100e18)
// โ 5e18 tokens sent to myERC20Token, 95e18 effective amount
// PHASE 2: tryHook(USDC, netAmount)
// โ 2% of USDC sent to myERC20Token, Alice gets remainder
// Verify hook tracking
assertEq(mockGlue.getHookAmountTransferred(myERC20Token), 5e18); // Sticky hook amount
assertGt(mockGlue.getHookAmountTransferred(USDC), 0); // USDC hook amount
assertEq(mockGlue.getHookExecutionCount(myERC20Token), 1); // Hook executed once
// Check hook status
assertEq(mockGlue.getHookStatus(), 2); // BIO.HOOK
assertTrue(mockGlue.hasHook()); // Hook interface simulation
}
}
```
#### 2. MockUnglueERC721 - Test Individual NFT Unglue Operations
**Focus**: Testing `IGlueERC721.unglue(collaterals, tokenIds[], recipient)` functionality with accurate NFT hook simulation.
```solidity
// Import and deploy
import "@glue-finance/expansions-pack/mocks/MockUnglueERC721.sol";
contract TestMyNFTStrategy {
MockUnglueERC721 mockGlue;
function setUp() public {
mockGlue = new MockUnglueERC721();
// Configure the mock
mockGlue.setStickyAsset(myNFTCollection);
mockGlue.setMockTotalSupply(10000); // 10k NFT collection
// Add collateral
mockGlue.addCollateral(USDC, 100000e6); // 100k USDC
mockGlue.addETH{value: 100e18}(); // 100 ETH
// Configure NFT hooks (special behavior!)
mockGlue.configureHooks(true, 0); // Enable hooks but sticky hook has no economic impact
mockGlue.setAssetHookSize(USDC, 2e16); // 2% USDC hook
}
function testNFTHookSimulation() public {
address[] memory collaterals = new address[](2);
collaterals[0] = USDC;
collaterals[1] = address(0); // ETH
uint256[] memory tokenIds = new uint256[](3);
tokenIds[0] = 1; tokenIds[1] = 2; tokenIds[2] = 3;
// Execute unglue - burn 3 NFTs
mockGlue.unglue(collaterals, tokenIds, alice);
// PHASE 1: tryHook(myNFTCollection, 3, [1,2,3])
// โ NO AMOUNT TRANSFERRED (key NFT difference!)
// โ Still calls executeHook with 3 and [1,2,3] for tracking
// โ Returns 0 (no amount reduction)
// PHASE 2: tryHook(USDC, netAmount, [1,2,3])
// โ 2% of USDC sent to myNFTCollection, Alice gets remainder
// Verify NFT hook tracking
assertEq(mockGlue.getHookAmountTransferred(myNFTCollection), 0); // NO TRANSFER for NFTs!
assertGt(mockGlue.getHookAmountTransferred(USDC), 0); // USDC hook amount transferred
assertEq(mockGlue.getHookExecutionCount(myNFTCollection), 1); // Hook executed for tracking
// Check NFT tracking
assertTrue(mockGlue.isTokenIdBurned(1));
assertTrue(mockGlue.isTokenIdBurned(2));
assertTrue(mockGlue.isTokenIdBurned(3));
// Verify executeHook call details
(address asset, uint256 amount, uint256[] memory ids, uint256 timestamp) =
mockGlue.getLastExecuteHookCall();
assertEq(asset, myNFTCollection);
assertEq(amount, 3); // NFT count passed to hook
assertEq(ids.length, 3); // Actual tokenIds passed
assertEq(ids[0], 1); assertEq(ids[1], 2); assertEq(ids[2], 3);
}
}
```
#### 3. MockBatchUnglueERC20 - Test Multi-Asset ERC20 Operations
**Focus**: Testing `IGlueStickERC20.batchUnglue(assets, amounts[], collaterals, recipients)` functionality with per-glue hook configuration.
```solidity
// Import and deploy
import "@glue-finance/expansions-pack/mocks/MockBatchUnglueERC20.sol";
contract TestMyERC20BatchStrategy {
MockBatchUnglueERC20 mockBatch;
function setUp() public {
mockBatch = new MockBatchUnglueERC20();
// Register multiple ERC20 tokens with their glues
mockBatch.registerStickyAsset(tokenA, mockGlueA);
mockBatch.registerStickyAsset(tokenB, mockGlueB);
// Set different total supplies
mockBatch.setMockTotalSupply(tokenA, 1000e18); // 1000 tokens for A
mockBatch.setMockTotalSupply(tokenB, 2000e18); // 2000 tokens for B
// Add collateral to each glue
mockBatch.addCollateralToGlue(mockGlueA, USDC, 1000e6);
mockBatch.addCollateralToGlue(mockGlueB, USDC, 2000e6);
// Configure hooks per glue (accurate simulation)
mockBatch.configureHooksForGlue(mockGlueA, true, 2e16); // 2% sticky hook for A
mockBatch.setAssetHookSizeForGlue(mockGlueA, USDC, 1e16); // 1% USDC hook for A
mockBatch.configureHooksForGlue(mockGlueB, false, 0); // No hooks for B
}
function testERC20BatchHooks() public {
address[] memory assets = new address[](2);
assets[0] = tokenA; assets[1] = tokenB;
uint256[] memory amounts = new uint256[](2);
amounts[0] = 100e18; amounts[1] = 200e18; // 10% from A, 10% from B
address[] memory collaterals = new address[](1);
collaterals[0] = USDC;
address[] memory recipients = new address[](1);
recipients[0] = alice;
// Execute batch unglue
mockBatch.batchUnglue(assets, amounts, collaterals, recipients);
// Verify per-glue hook behavior
assertGt(mockBatch.getHookAmountTransferredForGlue(mockGlueA, tokenA), 0); // Sticky hook A
assertGt(mockBatch.getHookAmountTransferredForGlue(mockGlueA, USDC), 0); // USDC hook A
assertEq(mockBatch.getHookAmountTransferredForGlue(mockGlueB, tokenB), 0); // No hooks B
assertEq(mockBatch.getHookAmountTransferredForGlue(mockGlueB, USDC), 0); // No hooks B
}
}
```
#### 4. MockBatchUnglueERC721 - Test Multi-Collection NFT Operations
**Focus**: Testing `IGlueStickERC721.batchUnglue(assets, tokenIds[][], collaterals, recipients)` functionality with NFT-specific hook behavior.
```solidity
// Import and deploy
import "@glue-finance/expansions-pack/mocks/MockBatchUnglueERC721.sol";
contract TestMyNFTBatchStrategy {
MockBatchUnglueERC721 mockBatch;
function testNFTBatchHooks() public {
// ... setup similar to above ...
// Create 2D tokenIds array
uint256[][] memory tokenIds = new uint256[][](2);
tokenIds[0] = new uint256[](3); // 3 NFTs from collection A
tokenIds[0][0] = 1; tokenIds[0][1] = 2; tokenIds[0][2] = 3;
tokenIds[1] = new uint256[](2); // 2 NFTs from collection B
tokenIds[1][0] = 100; tokenIds[1][1] = 200;
// Execute batch unglue
mockBatch.batchUnglue(assets, tokenIds, collaterals, recipients);
// Verify NFT-specific hook behavior
assertEq(mockBatch.getHookAmountTransferredForGlue(mockGlueA, collectionA), 0); // NO TRANSFER for NFTs!
assertGt(mockBatch.getHookExecutionCountForGlue(mockGlueA, collectionA), 0); // But hook was called for tracking
// Check NFT tracking per collection
assertTrue(mockBatch.isTokenIdBurnedForCollection(collectionA, 1));
assertTrue(mockBatch.isTokenIdBurnedForCollection(collectionB, 100));
}
}
```
### Hook Testing Helper Functions
All mock contracts include comprehensive helper functions for testing hook behavior:
```solidity
// Hook status and configuration
uint8 status = mock.getHookStatus(); // 0=UNCHECKED, 1=NO_HOOK, 2=HOOK
uint256 hookSize = mock.getAssetHookSize(USDC); // Get configured hook size
bool hasHooks = mock.hasHook(); // Simulates IGluedHooks.hasHook()
// Hook execution tracking
uint256 executions = mock.getHookExecutionCount(myToken); // Number of executeHook calls
uint256 transferred = mock.getHookAmountTransferred(USDC); // Total amount transferred via hooks
// Last executeHook call details (NFT contracts include tokenIds)
(address asset, uint256 amount, uint256[] memory tokenIds, uint256 timestamp) =
mock.getLastExecuteHookCall();
// Hook interface simulation (matches IGluedHooks)
uint256 hookSize = mock.hookSize(USDC, 1000e6); // Simulates hookSize() call
uint256 impact = mock.hooksImpact(USDC, 1000e6, 100e18); // Simulates hooksImpact() call
```
### Other Mock Contracts
- **MockFlashLoan.sol**: Test individual flash loan functionality
- **MockGluedLoan.sol**: Test cross-glue flash loans
- **MockStickyAsset.sol**: Mock sticky asset with configurable addresses (testing only)
- **MockGluedLoanReceiver.sol**: Mock flash loan receiver for testing
### Mock Contract Imports
```solidity
// Import specific mocks as needed
import "@glue-finance/expansions-pack/mocks/MockUnglueERC20.sol";
import "@glue-finance/expansions-pack/mocks/MockUnglueERC721.sol";
import "@glue-finance/expansions-pack/mocks/MockBatchUnglueERC20.sol";
import "@glue-finance/expansions-pack/mocks/MockBatchUnglueERC721.sol";
// Or import via index (includes all contracts)
import {MockUnglueERC20, MockUnglueERC721} from "@glue-finance/expansions-pack";
```
Each mock contract is **ultra-documented** with comprehensive examples, parameter explanations, and usage patterns. They're designed to make testing your Glue Protocol integrations as simple and reliable as possible, with **full interface compatibility** and **accurate protocol behavior including proper hook simulation**!
## Documentation
For detailed documentation and advanced usage examples, visit the [Glue Protocol Wiki](https://wiki.glue.finance).
## License
Most components of the Glue Protocol Expansions Pack are available under permissive open-source licenses. However, **StickyAsset.sol** is licensed under the [Business Source License 1.1](https://github.com/glue-finance/glue/blob/main/LICENCE.txt) with an end date of 2029-02-29 or a date specified at [v1-license-date.gluefinance.eth](https://v1-license-date.gluefinance.eth).
### StickyAsset License Terms (BUSL-1.1)
**StickyAsset.sol** can be **used and integrated freely** as long as it maintains operation with the official Glue Protocol addresses. This means you can:
โ
**Use StickyAsset freely** in your projects
โ
**Integrate with confidence** knowing it operates with official protocol addresses
โ
**Build and deploy** tokens that inherit from StickyAsset
โ
**Earn money** from your StickyAsset-based projects
The only requirement is that StickyAsset **must maintain integration** with the official Glue_Stick addresses.
### General Protocol License Terms
The protocol is permissionless - you can build on top of it for both public good and profit. However, you cannot fork and deploy your own version of the core protocol.
### Required Official Addresses
When using StickyAsset, your contract must interact with these official addresses:
- **GLUE_STICK_ERC20**: `0x0ddE8dda9f486a4EC5eece60a59248bD28144dFf`
- **GLUE_STICK_ERC721**: `0xe9B08D7dC8e44F1973269E7cE0fe98297668C257`
### Other Components
All other components (interfaces, libraries, examples, mocks) are available under permissive open-source licenses.
## Security
This project is provided "as is" and may contain bugs or security vulnerabilities. Please use at your own risk and consider getting a security audit before using in production.
## Links
- [Website](https://glue.finance)
- [Wiki](https://wiki.glue.finance)
- [GitHub](https://github.com/glue-finance)
- [Discord](https://discord.gg/glue-finance)