diff --git a/README.md b/README.md
index 09a5f30b6..4fb842b9a 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ In-depth documentation is available at [docs.sablier.com](https://docs.sablier.c
## Background
Sablier Lockup Protocol is a token distribution protocol used by DAOs and businesses for vesting, payroll, airdrops, and
-more. Our flagship model is the linear stream, which distributes assets on a continuous, by-the-second basis.
+more. Our flagship model is the linear stream, which distributes tokens on a continuous, by-the-second basis.
The way it works is that the sender of a payment stream first deposits a specific amount of ERC-20 tokens in a contract.
Then, the contract progressively allocates the funds to the recipient, who can access them as they become available over
diff --git a/SECURITY.md b/SECURITY.md
index 411bc3d6c..c518bd062 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -87,7 +87,7 @@ publicly for their contribution if they so choose.
To qualify for a reward under this Program, you must adhere to the following criteria:
-- Identify a previously unreported, non-public vulnerability that could result in the loss or freeze of any ERC-20 asset
+- Identify a previously unreported, non-public vulnerability that could result in the loss or freeze of any ERC-20 token
in Sablier Lockup (but not on any third-party platform interacting with Sablier Lockup) and that is within the scope
of this Program.
- The vulnerability must be distinct from the issues covered in the [Audits](https://github.com/sablier-labs/audits).
diff --git a/script/GenerateSVG.s.sol b/script/GenerateSVG.s.sol
index 47b7d4964..6b1bac990 100644
--- a/script/GenerateSVG.s.sol
+++ b/script/GenerateSVG.s.sol
@@ -33,8 +33,8 @@ contract GenerateSVG is BaseScript, LockupNFTDescriptor {
NFTSVG.SVGParams({
accentColor: generateAccentColor({ sablier: LOCKUP, streamId: uint256(keccak256(msg.data)) }),
amount: string.concat(SVGElements.SIGN_GE, " ", amount),
- assetAddress: DAI.toHexString(),
- assetSymbol: "DAI",
+ tokenAddress: DAI.toHexString(),
+ tokenSymbol: "DAI",
duration: calculateDurationInDays({ startTime: 0, endTime: duration * 1 days }),
progress: stringifyPercentage(progress),
progressNumerical: progress,
diff --git a/script/Init.s.sol b/script/Init.s.sol
index 5799b21a4..fa4cfac37 100644
--- a/script/Init.s.sol
+++ b/script/Init.s.sol
@@ -17,7 +17,7 @@ interface IERC20Mint {
/// @notice Initializes the protocol by creating some streams.
contract Init is BaseScript {
- function run(ISablierLockup lockup, IERC20 asset) public broadcast {
+ function run(ISablierLockup lockup, IERC20 token) public broadcast {
address sender = broadcaster;
address recipient = vm.addr(vm.deriveKey({ mnemonic: mnemonic, index: 1 }));
@@ -25,11 +25,11 @@ contract Init is BaseScript {
LOCKUP-LINEAR
//////////////////////////////////////////////////////////////////////////*/
- // Mint enough assets to the sender.
- IERC20Mint(address(asset)).mint({ beneficiary: sender, value: 131_601.1e18 + 10_000e18 });
+ // Mint enough tokens to the sender.
+ IERC20Mint(address(token)).mint({ beneficiary: sender, value: 131_601.1e18 + 10_000e18 });
- // Approve the Lockup contracts to transfer the ERC-20 assets from the sender.
- asset.approve({ spender: address(lockup), value: type(uint256).max });
+ // Approve the Lockup contracts to transfer the ERC-20 tokens from the sender.
+ token.approve({ spender: address(lockup), value: type(uint256).max });
// Create 7 Lockup Linear streams with various amounts and durations.
//
@@ -48,7 +48,7 @@ contract Init is BaseScript {
sender: sender,
recipient: recipient,
totalAmount: totalAmounts[i],
- asset: asset,
+ token: token,
cancelable: true,
transferable: true,
broker: Broker(address(0), ud60x18(0)),
@@ -80,7 +80,7 @@ contract Init is BaseScript {
sender: sender,
recipient: recipient,
totalAmount: 10_000e18,
- asset: asset,
+ token: token,
cancelable: true,
transferable: true,
broker: Broker(address(0), ud60x18(0)),
diff --git a/src/LockupNFTDescriptor.sol b/src/LockupNFTDescriptor.sol
index 3a9cafc4c..3f52571c2 100644
--- a/src/LockupNFTDescriptor.sol
+++ b/src/LockupNFTDescriptor.sol
@@ -44,8 +44,8 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
/// @dev Needed to avoid Stack Too Deep.
struct TokenURIVars {
- address asset;
- string assetSymbol;
+ address token;
+ string tokenSymbol;
uint128 depositedAmount;
bool isTransferable;
string json;
@@ -67,10 +67,21 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
vars.lockup = ISablierLockup(address(lockup));
vars.lockupModel = mapSymbol(lockup);
vars.lockupStringified = address(lockup).toHexString();
- vars.asset = address(vars.lockup.getAsset(streamId));
- vars.assetSymbol = safeAssetSymbol(vars.asset);
+ vars.tokenSymbol = safeTokenSymbol(vars.token);
vars.depositedAmount = vars.lockup.getDepositedAmount(streamId);
+ // Retrieve the token's address based on the Lockup contract version.
+ if (vars.lockupModel.equal("Sablier Lockup")) {
+ // For Lockup contract versions v2.0.0 and later, use the `getToken` function.
+ vars.token = address(vars.lockup.getToken(streamId));
+ }
+ // For Lockup contract versions earlier than v2.0.0, use the `getAsset` function.
+ else {
+ (, bytes memory returnData) =
+ address(lockup).staticcall(abi.encodeWithSignature("getAsset(uint256)", streamId));
+ vars.token = abi.decode(returnData, (address));
+ }
+
// Load the stream's data.
vars.status = stringifyStatus(vars.lockup.statusOf(streamId));
vars.streamedPercentage = calculateStreamedPercentage({
@@ -82,9 +93,9 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
vars.svg = NFTSVG.generateSVG(
NFTSVG.SVGParams({
accentColor: generateAccentColor(address(lockup), streamId),
- amount: abbreviateAmount({ amount: vars.depositedAmount, decimals: safeAssetDecimals(vars.asset) }),
- assetAddress: vars.asset.toHexString(),
- assetSymbol: vars.assetSymbol,
+ amount: abbreviateAmount({ amount: vars.depositedAmount, decimals: safeTokenDecimals(vars.token) }),
+ tokenAddress: vars.token.toHexString(),
+ tokenSymbol: vars.tokenSymbol,
duration: calculateDurationInDays({
startTime: vars.lockup.getStartTime(streamId),
endTime: vars.lockup.getEndTime(streamId)
@@ -108,16 +119,16 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
vars.json = string.concat(
'{"attributes":',
generateAttributes({
- assetSymbol: vars.assetSymbol,
+ tokenSymbol: vars.tokenSymbol,
sender: vars.lockup.getSender(streamId).toHexString(),
status: vars.status
}),
',"description":"',
generateDescription({
lockupModel: vars.lockupModel,
- assetSymbol: vars.assetSymbol,
+ tokenSymbol: vars.tokenSymbol,
lockupStringified: vars.lockupStringified,
- assetAddress: vars.asset.toHexString(),
+ tokenAddress: vars.token.toHexString(),
streamId: streamId.toString(),
isTransferable: vars.isTransferable
}),
@@ -249,12 +260,12 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
}
/// @notice Generates an array of JSON objects that represent the NFT's attributes:
- /// - Asset symbol
+ /// - Token symbol
/// - Sender address
/// - Status
/// @dev These attributes are useful for filtering and sorting the NFTs.
function generateAttributes(
- string memory assetSymbol,
+ string memory tokenSymbol,
string memory sender,
string memory status
)
@@ -263,8 +274,8 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
returns (string memory)
{
return string.concat(
- '[{"trait_type":"Asset","value":"',
- assetSymbol,
+ '[{"trait_type":"Token","value":"',
+ tokenSymbol,
'"},{"trait_type":"Sender","value":"',
sender,
'"},{"trait_type":"Status","value":"',
@@ -276,9 +287,9 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
/// @notice Generates a string with the NFT's JSON metadata description, which provides a high-level overview.
function generateDescription(
string memory lockupModel,
- string memory assetSymbol,
+ string memory tokenSymbol,
string memory lockupStringified,
- string memory assetAddress,
+ string memory tokenAddress,
string memory streamId,
bool isTransferable
)
@@ -295,8 +306,8 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
return string.concat(
"This NFT represents a payment stream in a Sablier Lockup ",
lockupModel,
- " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ",
- assetSymbol,
+ " contract. The owner of this NFT can withdraw the streamed tokens, which are denominated in ",
+ tokenSymbol,
".\\n\\n- Stream ID: ",
streamId,
"\\n- ",
@@ -304,9 +315,9 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
" Address: ",
lockupStringified,
"\\n- ",
- assetSymbol,
+ tokenSymbol,
" Address: ",
- assetAddress,
+ tokenAddress,
"\\n\\n",
info
);
@@ -358,10 +369,10 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
}
}
- /// @notice Retrieves the asset's decimals safely, defaulting to "0" if an error occurs.
- /// @dev Performs a low-level call to handle assets in which the decimals are not implemented.
- function safeAssetDecimals(address asset) internal view returns (uint8) {
- (bool success, bytes memory returnData) = asset.staticcall(abi.encodeCall(IERC20Metadata.decimals, ()));
+ /// @notice Retrieves the token's decimals safely, defaulting to "0" if an error occurs.
+ /// @dev Performs a low-level call to handle tokens in which the decimals are not implemented.
+ function safeTokenDecimals(address token) internal view returns (uint8) {
+ (bool success, bytes memory returnData) = token.staticcall(abi.encodeCall(IERC20Metadata.decimals, ()));
if (success && returnData.length == 32) {
return abi.decode(returnData, (uint8));
} else {
@@ -369,11 +380,11 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
}
}
- /// @notice Retrieves the asset's symbol safely, defaulting to a hard-coded value if an error occurs.
- /// @dev Performs a low-level call to handle assets in which the symbol is not implemented or it is a bytes32
+ /// @notice Retrieves the token's symbol safely, defaulting to a hard-coded value if an error occurs.
+ /// @dev Performs a low-level call to handle tokens in which the symbol is not implemented or it is a bytes32
/// instead of a string.
- function safeAssetSymbol(address asset) internal view returns (string memory) {
- (bool success, bytes memory returnData) = asset.staticcall(abi.encodeCall(IERC20Metadata.symbol, ()));
+ function safeTokenSymbol(address token) internal view returns (string memory) {
+ (bool success, bytes memory returnData) = token.staticcall(abi.encodeCall(IERC20Metadata.symbol, ()));
// Non-empty strings have a length greater than 64, and bytes32 has length 32.
if (!success || returnData.length <= 64) {
@@ -383,7 +394,7 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor {
string memory symbol = abi.decode(returnData, (string));
// Check if the symbol is too long or contains disallowed characters. This measure helps mitigate potential
- // security threats from malicious assets injecting scripts in the symbol string.
+ // security threats from malicious tokens injecting scripts in the symbol string.
if (bytes(symbol).length > 30) {
return "Long Symbol";
} else {
diff --git a/src/SablierBatchLockup.sol b/src/SablierBatchLockup.sol
index 1203e50c9..b7e3eab81 100644
--- a/src/SablierBatchLockup.sol
+++ b/src/SablierBatchLockup.sol
@@ -21,7 +21,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
/// @inheritdoc ISablierBatchLockup
function createWithDurationsLD(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithDurationsLD[] calldata batch
)
external
@@ -44,8 +44,8 @@ contract SablierBatchLockup is ISablierBatchLockup {
}
}
- // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of assets.
- _handleTransfer(address(lockup), asset, transferAmount);
+ // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of tokens.
+ _handleTransfer(address(lockup), token, transferAmount);
// Create a stream for each element in the parameter array.
streamIds = new uint256[](batchSize);
@@ -56,7 +56,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
sender: batch[i].sender,
recipient: batch[i].recipient,
totalAmount: batch[i].totalAmount,
- asset: asset,
+ token: token,
cancelable: batch[i].cancelable,
transferable: batch[i].transferable,
broker: batch[i].broker,
@@ -70,7 +70,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
/// @inheritdoc ISablierBatchLockup
function createWithTimestampsLD(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithTimestampsLD[] calldata batch
)
external
@@ -93,8 +93,8 @@ contract SablierBatchLockup is ISablierBatchLockup {
}
}
- // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of assets.
- _handleTransfer(address(lockup), asset, transferAmount);
+ // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of tokens.
+ _handleTransfer(address(lockup), token, transferAmount);
uint40 endTime;
@@ -112,7 +112,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
sender: batch[i].sender,
recipient: batch[i].recipient,
totalAmount: batch[i].totalAmount,
- asset: asset,
+ token: token,
cancelable: batch[i].cancelable,
transferable: batch[i].transferable,
timestamps: Lockup.Timestamps({ start: batch[i].startTime, end: endTime }),
@@ -131,7 +131,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
/// @inheritdoc ISablierBatchLockup
function createWithDurationsLL(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithDurationsLL[] calldata batch
)
external
@@ -154,8 +154,8 @@ contract SablierBatchLockup is ISablierBatchLockup {
}
}
- // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of assets.
- _handleTransfer(address(lockup), asset, transferAmount);
+ // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of tokens.
+ _handleTransfer(address(lockup), token, transferAmount);
// Create a stream for each element in the parameter array.
streamIds = new uint256[](batchSize);
@@ -166,7 +166,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
sender: batch[i].sender,
recipient: batch[i].recipient,
totalAmount: batch[i].totalAmount,
- asset: asset,
+ token: token,
cancelable: batch[i].cancelable,
transferable: batch[i].transferable,
broker: batch[i].broker,
@@ -181,7 +181,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
/// @inheritdoc ISablierBatchLockup
function createWithTimestampsLL(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithTimestampsLL[] calldata batch
)
external
@@ -204,8 +204,8 @@ contract SablierBatchLockup is ISablierBatchLockup {
}
}
- // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of assets.
- _handleTransfer(address(lockup), asset, transferAmount);
+ // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of tokens.
+ _handleTransfer(address(lockup), token, transferAmount);
// Create a stream for each element in the parameter array.
streamIds = new uint256[](batchSize);
@@ -216,7 +216,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
sender: batch[i].sender,
recipient: batch[i].recipient,
totalAmount: batch[i].totalAmount,
- asset: asset,
+ token: token,
cancelable: batch[i].cancelable,
transferable: batch[i].transferable,
timestamps: batch[i].timestamps,
@@ -236,7 +236,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
/// @inheritdoc ISablierBatchLockup
function createWithDurationsLT(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithDurationsLT[] calldata batch
)
external
@@ -259,8 +259,8 @@ contract SablierBatchLockup is ISablierBatchLockup {
}
}
- // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of assets.
- _handleTransfer(address(lockup), asset, transferAmount);
+ // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of tokens.
+ _handleTransfer(address(lockup), token, transferAmount);
// Create a stream for each element in the parameter array.
streamIds = new uint256[](batchSize);
@@ -271,7 +271,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
sender: batch[i].sender,
recipient: batch[i].recipient,
totalAmount: batch[i].totalAmount,
- asset: asset,
+ token: token,
cancelable: batch[i].cancelable,
transferable: batch[i].transferable,
broker: batch[i].broker,
@@ -285,7 +285,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
/// @inheritdoc ISablierBatchLockup
function createWithTimestampsLT(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithTimestampsLT[] calldata batch
)
external
@@ -308,8 +308,8 @@ contract SablierBatchLockup is ISablierBatchLockup {
}
}
- // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of assets.
- _handleTransfer(address(lockup), asset, transferAmount);
+ // Perform the ERC-20 transfer and approve {SablierLockup} to spend the amount of tokens.
+ _handleTransfer(address(lockup), token, transferAmount);
uint40 endTime;
@@ -327,7 +327,7 @@ contract SablierBatchLockup is ISablierBatchLockup {
sender: batch[i].sender,
recipient: batch[i].recipient,
totalAmount: batch[i].totalAmount,
- asset: asset,
+ token: token,
cancelable: batch[i].cancelable,
transferable: batch[i].transferable,
timestamps: Lockup.Timestamps({ start: batch[i].startTime, end: endTime }),
@@ -345,22 +345,22 @@ contract SablierBatchLockup is ISablierBatchLockup {
/// @dev Helper function to approve a Lockup contract to spend funds from the batchLockup. If the current allowance
/// is insufficient, this function approves Lockup to spend the exact `amount`.
- /// The {SafeERC20.forceApprove} function is used to handle special ERC-20 assets (e.g. USDT) that require the
+ /// The {SafeERC20.forceApprove} function is used to handle special ERC-20 tokens (e.g. USDT) that require the
/// current allowance to be zero before setting it to a non-zero value.
- function _approve(address lockup, IERC20 asset, uint256 amount) internal {
- uint256 allowance = asset.allowance({ owner: address(this), spender: lockup });
+ function _approve(address lockup, IERC20 token, uint256 amount) internal {
+ uint256 allowance = token.allowance({ owner: address(this), spender: lockup });
if (allowance < amount) {
- asset.forceApprove({ spender: lockup, value: amount });
+ token.forceApprove({ spender: lockup, value: amount });
}
}
- /// @dev Helper function to transfer assets from the caller to the batchLockup contract and approve the Lockup
+ /// @dev Helper function to transfer tokens from the caller to the batchLockup contract and approve the Lockup
/// contract.
- function _handleTransfer(address lockup, IERC20 asset, uint256 amount) internal {
- // Transfer the assets to the batchLockup contract.
- asset.safeTransferFrom({ from: msg.sender, to: address(this), value: amount });
+ function _handleTransfer(address lockup, IERC20 token, uint256 amount) internal {
+ // Transfer the tokens to the batchLockup contract.
+ token.safeTransferFrom({ from: msg.sender, to: address(this), value: amount });
// Approve the Lockup contract to spend funds.
- _approve(lockup, asset, amount);
+ _approve(lockup, token, amount);
}
}
diff --git a/src/SablierLockup.sol b/src/SablierLockup.sol
index d612786d0..d8cc8a224 100644
--- a/src/SablierLockup.sol
+++ b/src/SablierLockup.sol
@@ -154,7 +154,7 @@ contract SablierLockup is ISablierLockup, SablierLockupBase {
sender: params.sender,
recipient: params.recipient,
totalAmount: params.totalAmount,
- asset: params.asset,
+ token: params.token,
cancelable: params.cancelable,
transferable: params.transferable,
timestamps: timestamps,
@@ -198,7 +198,7 @@ contract SablierLockup is ISablierLockup, SablierLockupBase {
sender: params.sender,
recipient: params.recipient,
totalAmount: params.totalAmount,
- asset: params.asset,
+ token: params.token,
cancelable: params.cancelable,
transferable: params.transferable,
timestamps: timestamps,
@@ -234,7 +234,7 @@ contract SablierLockup is ISablierLockup, SablierLockupBase {
sender: params.sender,
recipient: params.recipient,
totalAmount: params.totalAmount,
- asset: params.asset,
+ token: params.token,
cancelable: params.cancelable,
transferable: params.transferable,
timestamps: timestamps,
@@ -363,7 +363,7 @@ contract SablierLockup is ISablierLockup, SablierLockupBase {
endTime: params.timestamps.end,
isCancelable: params.cancelable,
wasCanceled: false,
- asset: params.asset,
+ token: params.token,
isDepleted: false,
isStream: true,
isTransferable: params.transferable,
@@ -380,11 +380,11 @@ contract SablierLockup is ISablierLockup, SablierLockupBase {
}
// Interaction: transfer the deposit amount.
- params.asset.safeTransferFrom({ from: msg.sender, to: address(this), value: createAmounts.deposit });
+ params.token.safeTransferFrom({ from: msg.sender, to: address(this), value: createAmounts.deposit });
// Interaction: pay the broker fee, if not zero.
if (createAmounts.brokerFee > 0) {
- params.asset.safeTransferFrom({ from: msg.sender, to: params.broker.account, value: createAmounts.brokerFee });
+ params.token.safeTransferFrom({ from: msg.sender, to: params.broker.account, value: createAmounts.brokerFee });
}
return Lockup.CreateEventCommon({
@@ -392,7 +392,7 @@ contract SablierLockup is ISablierLockup, SablierLockupBase {
sender: params.sender,
recipient: params.recipient,
amounts: createAmounts,
- asset: params.asset,
+ token: params.token,
cancelable: params.cancelable,
transferable: params.transferable,
timestamps: params.timestamps,
diff --git a/src/abstracts/SablierLockupBase.sol b/src/abstracts/SablierLockupBase.sol
index 202bbc76e..6afe95ad4 100644
--- a/src/abstracts/SablierLockupBase.sol
+++ b/src/abstracts/SablierLockupBase.sol
@@ -41,7 +41,7 @@ abstract contract SablierLockupBase is
/// @inheritdoc ISablierLockupBase
ILockupNFTDescriptor public override nftDescriptor;
- /// @dev Mapping of contracts allowed to hook to Sablier when a stream is canceled or when assets are withdrawn.
+ /// @dev Mapping of contracts allowed to hook to Sablier when a stream is canceled or when tokens are withdrawn.
mapping(address recipient => bool allowed) internal _allowedToHook;
/// @dev Lockup streams mapped by unsigned integers.
@@ -74,8 +74,8 @@ abstract contract SablierLockupBase is
//////////////////////////////////////////////////////////////////////////*/
/// @inheritdoc ISablierLockupBase
- function getAsset(uint256 streamId) external view override notNull(streamId) returns (IERC20 asset) {
- asset = _streams[streamId].asset;
+ function getToken(uint256 streamId) external view override notNull(streamId) returns (IERC20 token) {
+ token = _streams[streamId].token;
}
/// @inheritdoc ISablierLockupBase
@@ -610,7 +610,7 @@ abstract contract SablierLockupBase is
// Effect: make the stream not cancelable anymore, because a stream can only be canceled once.
_streams[streamId].isCancelable = false;
- // Effect: if there are no assets left for the recipient to withdraw, mark the stream as depleted.
+ // Effect: if there are no tokens left for the recipient to withdraw, mark the stream as depleted.
if (recipientAmount == 0) {
_streams[streamId].isDepleted = true;
}
@@ -622,14 +622,14 @@ abstract contract SablierLockupBase is
address sender = _streams[streamId].sender;
address recipient = _ownerOf(streamId);
- // Retrieve the ERC-20 asset from storage.
- IERC20 asset = _streams[streamId].asset;
+ // Retrieve the ERC-20 token from storage.
+ IERC20 token = _streams[streamId].token;
// Interaction: refund the sender.
- asset.safeTransfer({ to: sender, value: senderAmount });
+ token.safeTransfer({ to: sender, value: senderAmount });
// Log the cancellation.
- emit ISablierLockupBase.CancelLockupStream(streamId, sender, recipient, asset, senderAmount, recipientAmount);
+ emit ISablierLockupBase.CancelLockupStream(streamId, sender, recipient, token, senderAmount, recipientAmount);
// Emit an ERC-4906 event to trigger an update of the NFT metadata.
emit MetadataUpdate({ _tokenId: streamId });
@@ -702,13 +702,13 @@ abstract contract SablierLockupBase is
_streams[streamId].isCancelable = false;
}
- // Retrieve the ERC-20 asset from storage.
- IERC20 asset = _streams[streamId].asset;
+ // Retrieve the ERC-20 token from storage.
+ IERC20 token = _streams[streamId].token;
// Interaction: perform the ERC-20 transfer.
- asset.safeTransfer({ to: to, value: amount });
+ token.safeTransfer({ to: to, value: amount });
// Log the withdrawal.
- emit ISablierLockupBase.WithdrawFromLockupStream(streamId, to, asset, amount);
+ emit ISablierLockupBase.WithdrawFromLockupStream(streamId, to, token, amount);
}
}
diff --git a/src/interfaces/ISablierBatchLockup.sol b/src/interfaces/ISablierBatchLockup.sol
index 057dca9cf..2c9795860 100644
--- a/src/interfaces/ISablierBatchLockup.sol
+++ b/src/interfaces/ISablierBatchLockup.sol
@@ -21,13 +21,13 @@ interface ISablierBatchLockup {
/// - All requirements from {ISablierLockup.createWithDurationsLD} must be met for each stream.
///
/// @param lockup The address of the {SablierLockup} contract.
- /// @param asset The contract address of the ERC-20 asset to be distributed.
+ /// @param token The contract address of the ERC-20 token to be distributed.
/// @param batch An array of structs, each encapsulating a subset of the parameters of
/// {SablierLockup.createWithDurationsLD}.
/// @return streamIds The ids of the newly created streams.
function createWithDurationsLD(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithDurationsLD[] calldata batch
)
external
@@ -40,13 +40,13 @@ interface ISablierBatchLockup {
/// - All requirements from {ISablierLockup.createWithTimestampsLD} must be met for each stream.
///
/// @param lockup The address of the {SablierLockup} contract.
- /// @param asset The contract address of the ERC-20 asset to be distributed.
+ /// @param token The contract address of the ERC-20 token to be distributed.
/// @param batch An array of structs, each encapsulating a subset of the parameters of
/// {SablierLockup.createWithTimestampsLD}.
/// @return streamIds The ids of the newly created streams.
function createWithTimestampsLD(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithTimestampsLD[] calldata batch
)
external
@@ -63,13 +63,13 @@ interface ISablierBatchLockup {
/// - All requirements from {ISablierLockup.createWithDurationsLL} must be met for each stream.
///
/// @param lockup The address of the {SablierLockup} contract.
- /// @param asset The contract address of the ERC-20 asset to be distributed.
+ /// @param token The contract address of the ERC-20 token to be distributed.
/// @param batch An array of structs, each encapsulating a subset of the parameters of
/// {SablierLockup.createWithDurationsLL}.
/// @return streamIds The ids of the newly created streams.
function createWithDurationsLL(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithDurationsLL[] calldata batch
)
external
@@ -82,13 +82,13 @@ interface ISablierBatchLockup {
/// - All requirements from {ISablierLockup.createWithTimestampsLL} must be met for each stream.
///
/// @param lockup The address of the {SablierLockup} contract.
- /// @param asset The contract address of the ERC-20 asset to be distributed.
+ /// @param token The contract address of the ERC-20 token to be distributed.
/// @param batch An array of structs, each encapsulating a subset of the parameters of
/// {SablierLockup.createWithTimestampsLL}.
/// @return streamIds The ids of the newly created streams.
function createWithTimestampsLL(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithTimestampsLL[] calldata batch
)
external
@@ -105,13 +105,13 @@ interface ISablierBatchLockup {
/// - All requirements from {ISablierLockup.createWithDurationsLT} must be met for each stream.
///
/// @param lockup The address of the {SablierLockup} contract.
- /// @param asset The contract address of the ERC-20 asset to be distributed.
+ /// @param token The contract address of the ERC-20 token to be distributed.
/// @param batch An array of structs, each encapsulating a subset of the parameters of
/// {SablierLockup.createWithDurationsLT}.
/// @return streamIds The ids of the newly created streams.
function createWithDurationsLT(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithDurationsLT[] calldata batch
)
external
@@ -124,13 +124,13 @@ interface ISablierBatchLockup {
/// - All requirements from {ISablierLockup.createWithTimestampsLT} must be met for each stream.
///
/// @param lockup The address of the {SablierLockup} contract.
- /// @param asset The contract address of the ERC-20 asset to be distributed.
+ /// @param token The contract address of the ERC-20 token to be distributed.
/// @param batch An array of structs, each encapsulating a subset of the parameters of
/// {SablierLockup.createWithTimestampsLT}.
/// @return streamIds The ids of the newly created streams.
function createWithTimestampsLT(
ISablierLockup lockup,
- IERC20 asset,
+ IERC20 token,
BatchLockup.CreateWithTimestampsLT[] calldata batch
)
external
diff --git a/src/interfaces/ISablierLockup.sol b/src/interfaces/ISablierLockup.sol
index 98ca53e61..03e0404b9 100644
--- a/src/interfaces/ISablierLockup.sol
+++ b/src/interfaces/ISablierLockup.sol
@@ -163,7 +163,7 @@ interface ISablierLockup is ISablierLockupBase {
/// - The sum of the segment amounts must equal the deposit amount.
/// - `params.recipient` must not be the zero address.
/// - `params.sender` must not be the zero address.
- /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets.
+ /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` tokens.
///
/// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}.
/// @param segments Segments used to compose the dynamic distribution function.
@@ -197,7 +197,7 @@ interface ISablierLockup is ISablierLockupBase {
/// - The sum of `params.unlockAmounts.start` and `params.unlockAmounts.cliff` must be less than or equal to
/// deposit amount.
/// - If `params.timestamps.cliff` not set, the `params.unlockAmounts.cliff` must be zero.
- /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets.
+ /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` tokens.
///
/// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}.
/// @param cliffTime The Unix timestamp for the cliff period's end. A value of zero means there is no cliff.
@@ -233,7 +233,7 @@ interface ISablierLockup is ISablierLockupBase {
/// - The sum of the tranche amounts must equal the deposit amount.
/// - `params.recipient` must not be the zero address.
/// - `params.sender` must not be the zero address.
- /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets.
+ /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` tokens.
///
/// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}.
/// @param tranches Tranches used to compose the tranched distribution function.
diff --git a/src/interfaces/ISablierLockupBase.sol b/src/interfaces/ISablierLockupBase.sol
index 36bda8d2e..7b1a66bb0 100644
--- a/src/interfaces/ISablierLockupBase.sol
+++ b/src/interfaces/ISablierLockupBase.sol
@@ -32,16 +32,16 @@ interface ISablierLockupBase is
/// @param streamId The ID of the stream.
/// @param sender The address of the stream's sender.
/// @param recipient The address of the stream's recipient.
- /// @param asset The contract address of the ERC-20 asset that has been distributed.
- /// @param senderAmount The amount of assets refunded to the stream's sender, denoted in units of the asset's
+ /// @param token The contract address of the ERC-20 token that has been distributed.
+ /// @param senderAmount The amount of tokens refunded to the stream's sender, denoted in units of the token's
/// decimals.
- /// @param recipientAmount The amount of assets left for the stream's recipient to withdraw, denoted in units of the
- /// asset's decimals.
+ /// @param recipientAmount The amount of tokens left for the stream's recipient to withdraw, denoted in units of the
+ /// token's decimals.
event CancelLockupStream(
uint256 streamId,
address indexed sender,
address indexed recipient,
- IERC20 indexed asset,
+ IERC20 indexed token,
uint128 senderAmount,
uint128 recipientAmount
);
@@ -63,12 +63,12 @@ interface ISablierLockupBase is
address indexed admin, ILockupNFTDescriptor oldNFTDescriptor, ILockupNFTDescriptor newNFTDescriptor
);
- /// @notice Emitted when assets are withdrawn from a stream.
+ /// @notice Emitted when tokens are withdrawn from a stream.
/// @param streamId The ID of the stream.
- /// @param to The address that has received the withdrawn assets.
- /// @param asset The contract address of the ERC-20 asset that has been withdrawn.
- /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals.
- event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, IERC20 indexed asset, uint128 amount);
+ /// @param to The address that has received the withdrawn tokens.
+ /// @param token The contract address of the ERC-20 token that has been withdrawn.
+ /// @param amount The amount of tokens withdrawn, denoted in units of the token's decimals.
+ event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, IERC20 indexed token, uint128 amount);
/*//////////////////////////////////////////////////////////////////////////
CONSTANT FUNCTIONS
@@ -79,12 +79,12 @@ interface ISablierLockupBase is
/// @dev This value is hard coded as a constant.
function MAX_BROKER_FEE() external view returns (UD60x18);
- /// @notice Retrieves the address of the ERC-20 asset being distributed.
+ /// @notice Retrieves the address of the ERC-20 token being distributed.
/// @dev Reverts if `streamId` references a null stream.
/// @param streamId The stream ID for the query.
- function getAsset(uint256 streamId) external view returns (IERC20 asset);
+ function getToken(uint256 streamId) external view returns (IERC20 token);
- /// @notice Retrieves the amount deposited in the stream, denoted in units of the asset's decimals.
+ /// @notice Retrieves the amount deposited in the stream, denoted in units of the token's decimals.
/// @dev Reverts if `streamId` references a null stream.
/// @param streamId The stream ID for the query.
function getDepositedAmount(uint256 streamId) external view returns (uint128 depositedAmount);
@@ -104,7 +104,7 @@ interface ISablierLockupBase is
/// @param streamId The stream ID for the query.
function getRecipient(uint256 streamId) external view returns (address recipient);
- /// @notice Retrieves the amount refunded to the sender after a cancellation, denoted in units of the asset's
+ /// @notice Retrieves the amount refunded to the sender after a cancellation, denoted in units of the token's
/// decimals. This amount is always zero unless the stream was canceled.
/// @dev Reverts if `streamId` references a null stream.
/// @param streamId The stream ID for the query.
@@ -120,13 +120,13 @@ interface ISablierLockupBase is
/// @param streamId The stream ID for the query.
function getStartTime(uint256 streamId) external view returns (uint40 startTime);
- /// @notice Retrieves the amount withdrawn from the stream, denoted in units of the asset's decimals.
+ /// @notice Retrieves the amount withdrawn from the stream, denoted in units of the token's decimals.
/// @dev Reverts if `streamId` references a null stream.
/// @param streamId The stream ID for the query.
function getWithdrawnAmount(uint256 streamId) external view returns (uint128 withdrawnAmount);
/// @notice Retrieves a flag indicating whether the provided address is a contract allowed to hook to Sablier
- /// when a stream is canceled or when assets are withdrawn.
+ /// when a stream is canceled or when tokens are withdrawn.
/// @dev See {ISablierLockupRecipient} for more information.
function isAllowedToHook(address recipient) external view returns (bool result);
@@ -168,7 +168,7 @@ interface ISablierLockupBase is
function nftDescriptor() external view returns (ILockupNFTDescriptor);
/// @notice Calculates the amount that the sender would be refunded if the stream were canceled, denoted in units
- /// of the asset's decimals.
+ /// of the token's decimals.
/// @dev Reverts if `streamId` references a null stream.
/// @param streamId The stream ID for the query.
function refundableAmountOf(uint256 streamId) external view returns (uint128 refundableAmount);
@@ -178,7 +178,7 @@ interface ISablierLockupBase is
/// @param streamId The stream ID for the query.
function statusOf(uint256 streamId) external view returns (Lockup.Status status);
- /// @notice Calculates the amount streamed to the recipient, denoted in units of the asset's decimals.
+ /// @notice Calculates the amount streamed to the recipient, denoted in units of the token's decimals.
/// @dev Reverts if `streamId` references a null stream.
///
/// Notes:
@@ -194,7 +194,7 @@ interface ISablierLockupBase is
/// @param streamId The stream ID for the query.
function wasCanceled(uint256 streamId) external view returns (bool result);
- /// @notice Calculates the amount that the recipient can withdraw from the stream, denoted in units of the asset's
+ /// @notice Calculates the amount that the recipient can withdraw from the stream, denoted in units of the token's
/// decimals.
/// @dev Reverts if `streamId` references a null stream.
/// @param streamId The stream ID for the query.
@@ -204,7 +204,7 @@ interface ISablierLockupBase is
NON-CONSTANT FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
- /// @notice Allows a recipient contract to hook to Sablier when a stream is canceled or when assets are withdrawn.
+ /// @notice Allows a recipient contract to hook to Sablier when a stream is canceled or when tokens are withdrawn.
/// Useful for implementing contracts that hold streams on behalf of users, such as vaults or staking contracts.
///
/// @dev Emits an {AllowToHook} event.
@@ -234,12 +234,12 @@ interface ISablierLockupBase is
/// @param streamId The ID of the stream NFT to burn.
function burn(uint256 streamId) external payable;
- /// @notice Cancels the stream and refunds any remaining assets to the sender.
+ /// @notice Cancels the stream and refunds any remaining tokens to the sender.
///
/// @dev Emits a {Transfer}, {CancelLockupStream}, and {MetadataUpdate} event.
///
/// Notes:
- /// - If there any assets left for the recipient to withdraw, the stream is marked as canceled. Otherwise, the
+ /// - If there any tokens left for the recipient to withdraw, the stream is marked as canceled. Otherwise, the
/// stream is marked as depleted.
/// - This function attempts to invoke a hook on the recipient, if the resolved address is a contract.
///
@@ -251,7 +251,7 @@ interface ISablierLockupBase is
/// @param streamId The ID of the stream to cancel.
function cancel(uint256 streamId) external payable;
- /// @notice Cancels multiple streams and refunds any remaining assets to the sender.
+ /// @notice Cancels multiple streams and refunds any remaining tokens to the sender.
///
/// @dev Emits multiple {Transfer}, {CancelLockupStream}, and {MetadataUpdate} events.
///
@@ -314,7 +314,7 @@ interface ISablierLockupBase is
/// @param newNFTDescriptor The address of the new NFT descriptor contract.
function setNFTDescriptor(ILockupNFTDescriptor newNFTDescriptor) external;
- /// @notice Withdraws the provided amount of assets from the stream to the `to` address.
+ /// @notice Withdraws the provided amount of tokens from the stream to the `to` address.
///
/// @dev Emits a {Transfer}, {WithdrawFromLockupStream}, and {MetadataUpdate} event.
///
@@ -329,8 +329,8 @@ interface ISablierLockupBase is
/// - `to` must be the recipient if `msg.sender` is not the stream's recipient or an approved third party.
///
/// @param streamId The ID of the stream to withdraw from.
- /// @param to The address receiving the withdrawn assets.
- /// @param amount The amount to withdraw, denoted in units of the asset's decimals.
+ /// @param to The address receiving the withdrawn tokens.
+ /// @param amount The amount to withdraw, denoted in units of the token's decimals.
function withdraw(uint256 streamId, address to, uint128 amount) external payable;
/// @notice Withdraws the maximum withdrawable amount from the stream to the provided address `to`.
@@ -344,8 +344,8 @@ interface ISablierLockupBase is
/// - Refer to the requirements in {withdraw}.
///
/// @param streamId The ID of the stream to withdraw from.
- /// @param to The address receiving the withdrawn assets.
- /// @return withdrawnAmount The amount withdrawn, denoted in units of the asset's decimals.
+ /// @param to The address receiving the withdrawn tokens.
+ /// @return withdrawnAmount The amount withdrawn, denoted in units of the token's decimals.
function withdrawMax(uint256 streamId, address to) external payable returns (uint128 withdrawnAmount);
/// @notice Withdraws the maximum withdrawable amount from the stream to the current recipient, and transfers the
@@ -364,7 +364,7 @@ interface ISablierLockupBase is
///
/// @param streamId The ID of the stream NFT to transfer.
/// @param newRecipient The address of the new owner of the stream NFT.
- /// @return withdrawnAmount The amount withdrawn, denoted in units of the asset's decimals.
+ /// @return withdrawnAmount The amount withdrawn, denoted in units of the token's decimals.
function withdrawMaxAndTransfer(
uint256 streamId,
address newRecipient
@@ -373,7 +373,7 @@ interface ISablierLockupBase is
payable
returns (uint128 withdrawnAmount);
- /// @notice Withdraws assets from streams to the recipient of each stream.
+ /// @notice Withdraws tokens from streams to the recipient of each stream.
///
/// @dev Emits multiple {Transfer}, {WithdrawFromLockupStream}, and {MetadataUpdate} events.
///
@@ -387,6 +387,6 @@ interface ISablierLockupBase is
/// - Each amount in the array must be greater than zero and must not exceed the withdrawable amount.
///
/// @param streamIds The IDs of the streams to withdraw from.
- /// @param amounts The amounts to withdraw, denoted in units of the asset's decimals.
+ /// @param amounts The amounts to withdraw, denoted in units of the token's decimals.
function withdrawMultiple(uint256[] calldata streamIds, uint128[] calldata amounts) external payable;
}
diff --git a/src/interfaces/ISablierLockupRecipient.sol b/src/interfaces/ISablierLockupRecipient.sol
index cf6c80cb3..4dc33f0e4 100644
--- a/src/interfaces/ISablierLockupRecipient.sol
+++ b/src/interfaces/ISablierLockupRecipient.sol
@@ -19,10 +19,10 @@ interface ISablierLockupRecipient is IERC165 {
///
/// @param streamId The ID of the canceled stream.
/// @param sender The stream's sender, who canceled the stream.
- /// @param senderAmount The amount of assets refunded to the stream's sender, denoted in units of the asset's
+ /// @param senderAmount The amount of tokens refunded to the stream's sender, denoted in units of the token's
/// decimals.
- /// @param recipientAmount The amount of assets left for the stream's recipient to withdraw, denoted in units of
- /// the asset's decimals.
+ /// @param recipientAmount The amount of tokens left for the stream's recipient to withdraw, denoted in units of
+ /// the token's decimals.
///
/// @return selector The selector of this function needed to validate the hook.
function onSablierLockupCancel(
@@ -42,8 +42,8 @@ interface ISablierLockupRecipient is IERC165 {
///
/// @param streamId The ID of the stream being withdrawn from.
/// @param caller The original `msg.sender` address that triggered the withdrawal.
- /// @param to The address receiving the withdrawn assets.
- /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals.
+ /// @param to The address receiving the withdrawn tokens.
+ /// @param amount The amount of tokens withdrawn, denoted in units of the token's decimals.
///
/// @return selector The selector of this function needed to validate the hook.
function onSablierLockupWithdraw(
diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol
index 724280ea4..ba872b207 100644
--- a/src/libraries/Errors.sol
+++ b/src/libraries/Errors.sol
@@ -158,7 +158,7 @@ library Errors {
/// @notice Thrown when trying to withdraw to an address other than the recipient's.
error SablierLockupBase_WithdrawalAddressNotRecipient(uint256 streamId, address caller, address to);
- /// @notice Thrown when trying to withdraw zero assets from a stream.
+ /// @notice Thrown when trying to withdraw zero tokens from a stream.
error SablierLockupBase_WithdrawAmountZero(uint256 streamId);
/// @notice Thrown when trying to withdraw from multiple streams and the number of stream IDs does
diff --git a/src/libraries/NFTSVG.sol b/src/libraries/NFTSVG.sol
index ad2b736dc..5bbf0dd0a 100644
--- a/src/libraries/NFTSVG.sol
+++ b/src/libraries/NFTSVG.sol
@@ -14,8 +14,8 @@ library NFTSVG {
struct SVGParams {
string accentColor;
string amount;
- string assetAddress;
- string assetSymbol;
+ string tokenAddress;
+ string tokenSymbol;
string duration;
string lockupAddress;
string lockupModel;
@@ -89,7 +89,7 @@ library NFTSVG {
'"
);
@@ -120,8 +120,8 @@ library NFTSVG {
function generateFloatingText(
string memory lockupAddress,
string memory lockupModel,
- string memory assetAddress,
- string memory assetSymbol
+ string memory tokenAddress,
+ string memory tokenSymbol
)
internal
pure
@@ -137,8 +137,8 @@ library NFTSVG {
offset: "0%",
text: string.concat(lockupAddress, unicode" • ", "Sablier ", lockupModel)
}),
- SVGElements.floatingText({ offset: "-50%", text: string.concat(assetAddress, unicode" • ", assetSymbol) }),
- SVGElements.floatingText({ offset: "50%", text: string.concat(assetAddress, unicode" • ", assetSymbol) }),
+ SVGElements.floatingText({ offset: "-50%", text: string.concat(tokenAddress, unicode" • ", tokenSymbol) }),
+ SVGElements.floatingText({ offset: "50%", text: string.concat(tokenAddress, unicode" • ", tokenSymbol) }),
""
);
}
diff --git a/src/libraries/VestingMath.sol b/src/libraries/VestingMath.sol
index bf2428491..c4255326c 100644
--- a/src/libraries/VestingMath.sol
+++ b/src/libraries/VestingMath.sol
@@ -83,7 +83,7 @@ library VestingMath {
SD59x18 segmentStreamedAmount = multiplier.mul(currentSegmentAmount);
// Although the segment streamed amount should never exceed the total segment amount, this condition is
- // checked without asserting to avoid locking assets in case of a bug. If this situation occurs, the
+ // checked without asserting to avoid locking tokens in case of a bug. If this situation occurs, the
// amount streamed in the segment is considered zero (except for past withdrawals), and the segment is
// effectively voided.
if (segmentStreamedAmount.gt(currentSegmentAmount)) {
@@ -157,7 +157,7 @@ library VestingMath {
uint128 streamedAmount = unlockAmountsSum + (elapsedTimePercentage.mul(streamableAmount)).intoUint128();
// Although the streamed amount should never exceed the deposited amount, this condition is checked
- // without asserting to avoid locking assets in case of a bug. If this situation occurs, the withdrawn
+ // without asserting to avoid locking tokens in case of a bug. If this situation occurs, the withdrawn
// amount is considered to be the streamed amount, and the stream is effectively frozen.
if (streamedAmount > depositedAmount) {
return withdrawnAmount;
diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol
index 66231417a..5f38053cd 100644
--- a/src/types/DataTypes.sol
+++ b/src/types/DataTypes.sol
@@ -19,7 +19,7 @@ import { UD60x18 } from "@prb/math/src/UD60x18.sol";
/// @dev Namespace for the structs used in `BatchLockup` contract.
library BatchLockup {
- /// @notice A struct encapsulating all parameters of {SablierLockup.createWithDurationsLD} except for the asset.
+ /// @notice A struct encapsulating all parameters of {SablierLockup.createWithDurationsLD} except for the token.
struct CreateWithDurationsLD {
address sender;
address recipient;
@@ -31,7 +31,7 @@ library BatchLockup {
string shape;
}
- /// @notice A struct encapsulating all parameters of {SablierLockup.createWithDurationsLL} except for the asset.
+ /// @notice A struct encapsulating all parameters of {SablierLockup.createWithDurationsLL} except for the token.
struct CreateWithDurationsLL {
address sender;
address recipient;
@@ -44,7 +44,7 @@ library BatchLockup {
string shape;
}
- /// @notice A struct encapsulating all parameters of {SablierLockup.createWithDurationsLT} except for the asset.
+ /// @notice A struct encapsulating all parameters of {SablierLockup.createWithDurationsLT} except for the token.
struct CreateWithDurationsLT {
address sender;
address recipient;
@@ -56,7 +56,7 @@ library BatchLockup {
string shape;
}
- /// @notice A struct encapsulating all parameters of {SablierLockup.createWithTimestampsLD} except for the asset.
+ /// @notice A struct encapsulating all parameters of {SablierLockup.createWithTimestampsLD} except for the token.
struct CreateWithTimestampsLD {
address sender;
address recipient;
@@ -69,7 +69,7 @@ library BatchLockup {
string shape;
}
- /// @notice A struct encapsulating all parameters of {SablierLockup.createWithTimestampsLL} except for the asset.
+ /// @notice A struct encapsulating all parameters of {SablierLockup.createWithTimestampsLL} except for the token.
struct CreateWithTimestampsLL {
address sender;
address recipient;
@@ -83,7 +83,7 @@ library BatchLockup {
string shape;
}
- /// @notice A struct encapsulating all parameters of {SablierLockup.createWithTimestampsLT} except for the asset.
+ /// @notice A struct encapsulating all parameters of {SablierLockup.createWithTimestampsLT} except for the token.
struct CreateWithTimestampsLT {
address sender;
address recipient;
@@ -107,7 +107,7 @@ struct Broker {
/// @notice Namespace for the structs used in all Lockup models.
library Lockup {
- /// @notice Struct encapsulating the deposit, withdrawn, and refunded amounts, all denoted in units of the asset's
+ /// @notice Struct encapsulating the deposit, withdrawn, and refunded amounts, all denoted in units of the token's
/// decimals.
/// @dev Because the deposited and the withdrawn amount are often read together, declaring them in the same slot
/// saves gas.
@@ -123,7 +123,7 @@ library Lockup {
}
/// @notice Struct encapsulating (i) the deposit amount and (ii) the broker fee amount, both denoted in units of the
- /// asset's decimals.
+ /// token's decimals.
/// @param deposit The amount to deposit in the stream.
/// @param brokerFee The broker fee amount.
struct CreateAmounts {
@@ -133,11 +133,11 @@ library Lockup {
/// @notice Struct encapsulating the common parameters emitted in the `Create` event.
/// @param funder The address which has funded the stream.
- /// @param sender The address distributing the assets, which is able to cancel the stream.
- /// @param recipient The address receiving the assets, as well as the NFT owner.
+ /// @param sender The address distributing the tokens, which is able to cancel the stream.
+ /// @param recipient The address receiving the tokens, as well as the NFT owner.
/// @param amounts Struct encapsulating (i) the deposit amount, and (ii) the broker fee amount, both denoted
- /// in units of the asset's decimals.
- /// @param asset The contract address of the ERC-20 asset to be distributed.
+ /// in units of the token's decimals.
+ /// @param token The contract address of the ERC-20 token to be distributed.
/// @param cancelable Boolean indicating whether the stream is cancelable or not.
/// @param transferable Boolean indicating whether the stream NFT is transferable or not.
/// @param timestamps Struct encapsulating (i) the stream's start time and (ii) end time, all as Unix timestamps.
@@ -149,7 +149,7 @@ library Lockup {
address sender;
address recipient;
Lockup.CreateAmounts amounts;
- IERC20 asset;
+ IERC20 token;
bool cancelable;
bool transferable;
Lockup.Timestamps timestamps;
@@ -158,12 +158,12 @@ library Lockup {
}
/// @notice Struct encapsulating the parameters of the `createWithDurations` functions.
- /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be
+ /// @param sender The address distributing the tokens, with the ability to cancel the stream. It doesn't have to be
/// the same as `msg.sender`.
- /// @param recipient The address receiving the assets, as well as the NFT owner.
- /// @param totalAmount The total amount, including the deposit and any broker fee, denoted in units of the asset's
+ /// @param recipient The address receiving the tokens, as well as the NFT owner.
+ /// @param totalAmount The total amount, including the deposit and any broker fee, denoted in units of the token's
/// decimals.
- /// @param asset The contract address of the ERC-20 asset to be distributed.
+ /// @param token The contract address of the ERC-20 token to be distributed.
/// @param cancelable Indicates if the stream is cancelable.
/// @param transferable Indicates if the stream NFT is transferable.
/// @param broker Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the
@@ -174,7 +174,7 @@ library Lockup {
address sender;
address recipient;
uint128 totalAmount;
- IERC20 asset;
+ IERC20 token;
bool cancelable;
bool transferable;
Broker broker;
@@ -182,12 +182,12 @@ library Lockup {
}
/// @notice Struct encapsulating the parameters of the `createWithTimestamps` functions.
- /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be
+ /// @param sender The address distributing the tokens, with the ability to cancel the stream. It doesn't have to be
/// the same as `msg.sender`.
- /// @param recipient The address receiving the assets, as well as the NFT owner.
- /// @param totalAmount The total amount, including the deposit and any broker fee, denoted in units of the asset's
+ /// @param recipient The address receiving the tokens, as well as the NFT owner.
+ /// @param totalAmount The total amount, including the deposit and any broker fee, denoted in units of the token's
/// decimals.
- /// @param asset The contract address of the ERC-20 asset to be distributed.
+ /// @param token The contract address of the ERC-20 token to be distributed.
/// @param cancelable Indicates if the stream is cancelable.
/// @param transferable Indicates if the stream NFT is transferable.
/// @param timestamps Struct encapsulating (i) the stream's start time and (ii) end time, both as Unix timestamps.
@@ -199,7 +199,7 @@ library Lockup {
address sender;
address recipient;
uint128 totalAmount;
- IERC20 asset;
+ IERC20 token;
bool cancelable;
bool transferable;
Timestamps timestamps;
@@ -208,7 +208,7 @@ library Lockup {
}
/// @notice Enum representing the different distribution models used to create lockup streams.
- /// @dev These distribution models determine the vesting function used in the calculations of the unlocked assets.
+ /// @dev These distribution models determine the vesting function used in the calculations of the unlocked tokens.
enum Model {
LOCKUP_LINEAR,
LOCKUP_DYNAMIC,
@@ -219,11 +219,11 @@ library Lockup {
/// @dev The status can have a "temperature":
/// 1. Warm: Pending, Streaming. The passage of time alone can change the status.
/// 2. Cold: Settled, Canceled, Depleted. The passage of time alone cannot change the status.
- /// @custom:value0 PENDING Stream created but not started; assets are in a pending state.
- /// @custom:value1 STREAMING Active stream where assets are currently being streamed.
- /// @custom:value2 SETTLED All assets have been streamed; recipient is due to withdraw them.
- /// @custom:value3 CANCELED Canceled stream; remaining assets await recipient's withdrawal.
- /// @custom:value4 DEPLETED Depleted stream; all assets have been withdrawn and/or refunded.
+ /// @custom:value0 PENDING Stream created but not started; tokens are in a pending state.
+ /// @custom:value1 STREAMING Active stream where tokens are currently being streamed.
+ /// @custom:value2 SETTLED All tokens have been streamed; recipient is due to withdraw them.
+ /// @custom:value3 CANCELED Canceled stream; remaining tokens await recipient's withdrawal.
+ /// @custom:value4 DEPLETED Depleted stream; all tokens have been withdrawn and/or refunded.
enum Status {
// Warm
PENDING,
@@ -236,18 +236,18 @@ library Lockup {
/// @notice A common data structure to be stored in all Lockup models.
/// @dev The fields are arranged like this to save gas via tight variable packing.
- /// @param sender The address distributing the assets, with the ability to cancel the stream.
+ /// @param sender The address distributing the tokens, with the ability to cancel the stream.
/// @param startTime The Unix timestamp indicating the stream's start.
/// @param endTime The Unix timestamp indicating the stream's end.
/// @param isCancelable Boolean indicating if the stream is cancelable.
/// @param wasCanceled Boolean indicating if the stream was canceled.
- /// @param asset The contract address of the ERC-20 asset to be distributed.
+ /// @param token The contract address of the ERC-20 token to be distributed.
/// @param isDepleted Boolean indicating if the stream is depleted.
/// @param isStream Boolean indicating if the struct entity exists.
/// @param isTransferable Boolean indicating if the stream NFT is transferable.
/// @param lockupModel The distribution model of the stream.
/// @param amounts Struct encapsulating the deposit, withdrawn, and refunded amounts, both denoted in units of the
- /// asset's decimals.
+ /// token's decimals.
struct Stream {
// slot 0
address sender;
@@ -256,7 +256,7 @@ library Lockup {
bool isCancelable;
bool wasCanceled;
// slot 1
- IERC20 asset;
+ IERC20 token;
bool isDepleted;
bool isStream;
bool isTransferable;
@@ -277,7 +277,7 @@ library Lockup {
/// @notice Namespace for the structs used only in Lockup Dynamic model.
library LockupDynamic {
/// @notice Segment struct to be stored in the Lockup Dynamic model.
- /// @param amount The amount of assets streamed in the segment, denoted in units of the asset's decimals.
+ /// @param amount The amount of tokens streamed in the segment, denoted in units of the token's decimals.
/// @param exponent The exponent of the segment, denoted as a fixed-point number.
/// @param timestamp The Unix timestamp indicating the segment's end.
struct Segment {
@@ -288,7 +288,7 @@ library LockupDynamic {
}
/// @notice Segment struct used at runtime in {SablierLockup.createWithDurationsLD} function.
- /// @param amount The amount of assets streamed in the segment, denoted in units of the asset's decimals.
+ /// @param amount The amount of tokens streamed in the segment, denoted in units of the token's decimals.
/// @param exponent The exponent of the segment, denoted as a fixed-point number.
/// @param duration The time difference in seconds between the segment and the previous one.
struct SegmentWithDuration {
@@ -323,7 +323,7 @@ library LockupLinear {
/// @notice Namespace for the structs used only in Lockup Tranched model.
library LockupTranched {
/// @notice Tranche struct to be stored in the Lockup Tranched model.
- /// @param amount The amount of assets to be unlocked in the tranche, denoted in units of the asset's decimals.
+ /// @param amount The amount of tokens to be unlocked in the tranche, denoted in units of the token's decimals.
/// @param timestamp The Unix timestamp indicating the tranche's end.
struct Tranche {
// slot 0
@@ -332,7 +332,7 @@ library LockupTranched {
}
/// @notice Tranche struct used at runtime in {SablierLockup.createWithDurationsLT} function.
- /// @param amount The amount of assets to be unlocked in the tranche, denoted in units of the asset's decimals.
+ /// @param amount The amount of tokens to be unlocked in the tranche, denoted in units of the token's decimals.
/// @param duration The time difference in seconds between the tranche and the previous one.
struct TrancheWithDuration {
uint128 amount;
diff --git a/tests/Base.t.sol b/tests/Base.t.sol
index 8b5175cce..8a921bd2b 100644
--- a/tests/Base.t.sol
+++ b/tests/Base.t.sol
@@ -76,7 +76,7 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi
// Deploy the defaults contract.
defaults = new Defaults();
- defaults.setAsset(dai);
+ defaults.setToken(dai);
// Deploy the protocol.
deployProtocolConditionally();
@@ -112,14 +112,14 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi
HELPERS
//////////////////////////////////////////////////////////////////////////*/
- /// @dev Approve `spender` to spend assets from `from`.
- function approveContract(IERC20 asset_, address from, address spender) internal {
+ /// @dev Approve `spender` to spend tokens from `from`.
+ function approveContract(IERC20 token_, address from, address spender) internal {
resetPrank({ msgSender: from });
- (bool success,) = address(asset_).call(abi.encodeCall(IERC20.approve, (spender, MAX_UINT256)));
+ (bool success,) = address(token_).call(abi.encodeCall(IERC20.approve, (spender, MAX_UINT256)));
success;
}
- /// @dev Approves all contracts to spend assets from the address passed.
+ /// @dev Approves all contracts to spend tokens from the address passed.
function approveProtocol(address from) internal {
resetPrank({ msgSender: from });
dai.approve({ spender: address(batchLockup), value: MAX_UINT256 });
@@ -128,7 +128,7 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi
usdt.approve({ spender: address(lockup), value: MAX_UINT256 });
}
- /// @dev Generates a user, labels its address, funds it with test assets, and approves the protocol contracts.
+ /// @dev Generates a user, labels its address, funds it with test tokens, and approves the protocol contracts.
function createUser(string memory name) internal returns (address payable) {
address payable user = payable(makeAddr(name));
vm.deal({ account: user, newBalance: 100 ether });
@@ -166,8 +166,8 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi
}
/// @dev Expects a call to {IERC20.transfer}.
- function expectCallToTransfer(IERC20 asset, address to, uint256 value) internal {
- vm.expectCall({ callee: address(asset), data: abi.encodeCall(IERC20.transfer, (to, value)) });
+ function expectCallToTransfer(IERC20 token, address to, uint256 value) internal {
+ vm.expectCall({ callee: address(token), data: abi.encodeCall(IERC20.transfer, (to, value)) });
}
/// @dev Expects a call to {IERC20.transferFrom}.
@@ -176,8 +176,8 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi
}
/// @dev Expects a call to {IERC20.transferFrom}.
- function expectCallToTransferFrom(IERC20 asset, address from, address to, uint256 value) internal {
- vm.expectCall({ callee: address(asset), data: abi.encodeCall(IERC20.transferFrom, (from, to, value)) });
+ function expectCallToTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
+ vm.expectCall({ callee: address(token), data: abi.encodeCall(IERC20.transferFrom, (from, to, value)) });
}
/// @dev Expects multiple calls to {IERC20.transfer}.
@@ -192,7 +192,7 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi
/// @dev Expects multiple calls to {IERC20.transferFrom}.
function expectMultipleCallsToTransferFrom(
- IERC20 asset,
+ IERC20 token,
uint64 count,
address from,
address to,
@@ -201,7 +201,7 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi
internal
{
vm.expectCall({
- callee: address(asset),
+ callee: address(token),
count: count,
data: abi.encodeCall(IERC20.transferFrom, (from, to, value))
});
diff --git a/tests/fork/Fork.t.sol b/tests/fork/Fork.t.sol
index f2300bbeb..d32220d28 100644
--- a/tests/fork/Fork.t.sol
+++ b/tests/fork/Fork.t.sol
@@ -11,17 +11,17 @@ abstract contract Fork_Test is Base_Test {
STATE VARIABLES
//////////////////////////////////////////////////////////////////////////*/
- IERC20 internal immutable FORK_ASSET;
- address internal immutable FORK_ASSET_HOLDER;
+ IERC20 internal immutable FORK_TOKEN;
+ address internal immutable FORK_TOKEN_HOLDER;
uint256 internal initialHolderBalance;
/*//////////////////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////////////////*/
- constructor(IERC20 forkAsset, address forkAssetHolder) {
- FORK_ASSET = forkAsset;
- FORK_ASSET_HOLDER = forkAssetHolder;
+ constructor(IERC20 forkToken, address forkTokenHolder) {
+ FORK_TOKEN = forkToken;
+ FORK_TOKEN_HOLDER = forkTokenHolder;
}
/*//////////////////////////////////////////////////////////////////////////
@@ -38,11 +38,11 @@ abstract contract Fork_Test is Base_Test {
// Label the contracts.
labelContracts();
- // Make the forked asset holder the caller in this test suite.
- resetPrank({ msgSender: FORK_ASSET_HOLDER });
+ // Make the forked token holder the caller in this test suite.
+ resetPrank({ msgSender: FORK_TOKEN_HOLDER });
- // Query the initial balance of the forked asset holder.
- initialHolderBalance = FORK_ASSET.balanceOf(FORK_ASSET_HOLDER);
+ // Query the initial balance of the forked token holder.
+ initialHolderBalance = FORK_TOKEN.balanceOf(FORK_TOKEN_HOLDER);
}
/*//////////////////////////////////////////////////////////////////////////
@@ -54,20 +54,20 @@ abstract contract Fork_Test is Base_Test {
// The protocol does not allow the zero address to interact with it.
vm.assume(sender != address(0) && recipient != address(0) && broker != address(0));
- // The goal is to not have overlapping users because the forked asset balance tests would fail otherwise.
+ // The goal is to not have overlapping users because the forked token balance tests would fail otherwise.
vm.assume(sender != recipient && sender != broker && recipient != broker);
- vm.assume(sender != FORK_ASSET_HOLDER && recipient != FORK_ASSET_HOLDER && broker != FORK_ASSET_HOLDER);
+ vm.assume(sender != FORK_TOKEN_HOLDER && recipient != FORK_TOKEN_HOLDER && broker != FORK_TOKEN_HOLDER);
vm.assume(sender != lockupContract && recipient != lockupContract && broker != lockupContract);
// Avoid users blacklisted by USDC or USDT.
- assumeNoBlacklisted(address(FORK_ASSET), sender);
- assumeNoBlacklisted(address(FORK_ASSET), recipient);
- assumeNoBlacklisted(address(FORK_ASSET), broker);
+ assumeNoBlacklisted(address(FORK_TOKEN), sender);
+ assumeNoBlacklisted(address(FORK_TOKEN), recipient);
+ assumeNoBlacklisted(address(FORK_TOKEN), broker);
}
/// @dev Labels the most relevant contracts.
function labelContracts() internal {
- vm.label({ account: address(FORK_ASSET), newLabel: IERC20Metadata(address(FORK_ASSET)).symbol() });
- vm.label({ account: FORK_ASSET_HOLDER, newLabel: "FORK_ASSET_HOLDER" });
+ vm.label({ account: address(FORK_TOKEN), newLabel: IERC20Metadata(address(FORK_TOKEN)).symbol() });
+ vm.label({ account: FORK_TOKEN_HOLDER, newLabel: "FORK_TOKEN_HOLDER" });
}
}
diff --git a/tests/fork/LockupDynamic.t.sol b/tests/fork/LockupDynamic.t.sol
index ce9ed8ec6..f144761cb 100644
--- a/tests/fork/LockupDynamic.t.sol
+++ b/tests/fork/LockupDynamic.t.sol
@@ -14,7 +14,7 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
CONSTRUCTOR
//////////////////////////////////////////////////////////////////////////*/
- constructor(IERC20 forkAsset, address forkAssetHolder) Fork_Test(forkAsset, forkAssetHolder) { }
+ constructor(IERC20 forkToken, address forkTokenHolder) Fork_Test(forkToken, forkTokenHolder) { }
/*//////////////////////////////////////////////////////////////////////////
SET-UP FUNCTION
@@ -23,9 +23,9 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
function setUp() public virtual override {
Fork_Test.setUp();
- // Approve {SablierLockup} to transfer the holder's assets.
- // We use a low-level call to ignore reverts because the asset can have the missing return value bug.
- (bool success,) = address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockup), MAX_UINT256)));
+ // Approve {SablierLockup} to transfer the holder's tokens.
+ // We use a low-level call to ignore reverts because the token can have the missing return value bug.
+ (bool success,) = address(FORK_TOKEN).call(abi.encodeCall(IERC20.approve, (address(lockup), MAX_UINT256)));
success;
}
@@ -126,15 +126,15 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
});
// Make the holder the caller.
- resetPrank(FORK_ASSET_HOLDER);
+ resetPrank(FORK_TOKEN_HOLDER);
/*//////////////////////////////////////////////////////////////////////////
CREATE
//////////////////////////////////////////////////////////////////////////*/
- // Load the pre-create asset balances.
+ // Load the pre-create token balances.
vars.balances =
- getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.broker.account));
+ getTokenBalances(address(FORK_TOKEN), Solarray.addresses(address(lockup), params.broker.account));
vars.initialLockupBalance = vars.balances[0];
vars.initialBrokerBalance = vars.balances[1];
@@ -149,11 +149,11 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
emit ISablierLockup.CreateLockupDynamicStream({
streamId: vars.streamId,
commonParams: Lockup.CreateEventCommon({
- funder: FORK_ASSET_HOLDER,
+ funder: FORK_TOKEN_HOLDER,
sender: params.sender,
recipient: params.recipient,
amounts: vars.createAmounts,
- asset: FORK_ASSET,
+ token: FORK_TOKEN,
cancelable: true,
transferable: true,
timestamps: vars.timestamps,
@@ -169,7 +169,7 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
sender: params.sender,
recipient: params.recipient,
totalAmount: vars.totalAmount,
- asset: FORK_ASSET,
+ token: FORK_TOKEN,
cancelable: true,
transferable: true,
timestamps: vars.timestamps,
@@ -185,7 +185,7 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
vars.isCancelable = vars.isSettled ? false : true;
// Assert that the stream has been created.
- assertEq(lockup.getAsset(vars.streamId), FORK_ASSET, "asset");
+ assertEq(lockup.getToken(vars.streamId), FORK_TOKEN, "token");
assertEq(lockup.getDepositedAmount(vars.streamId), vars.createAmounts.deposit, "depositedAmount");
assertEq(lockup.getEndTime(vars.streamId), vars.timestamps.end, "endTime");
assertEq(lockup.isCancelable(vars.streamId), vars.isCancelable, "isCancelable");
@@ -219,9 +219,9 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
vars.expectedNFTOwner = params.recipient;
assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-create NFT owner");
- // Load the post-create asset balances.
+ // Load the post-create token balances.
vars.balances = getTokenBalances(
- address(FORK_ASSET), Solarray.addresses(address(lockup), FORK_ASSET_HOLDER, params.broker.account)
+ address(FORK_TOKEN), Solarray.addresses(address(lockup), FORK_TOKEN_HOLDER, params.broker.account)
);
vars.actualLockupBalance = vars.balances[0];
vars.actualHolderBalance = vars.balances[1];
@@ -259,17 +259,17 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
// Only run the withdraw tests if the withdraw amount is not zero.
if (params.withdrawAmount > 0) {
- // Load the pre-withdraw asset balances.
+ // Load the pre-withdraw token balances.
vars.initialLockupBalance = vars.actualLockupBalance;
vars.initialLockupBalanceETH = address(lockup).balance;
- vars.initialRecipientBalance = FORK_ASSET.balanceOf(params.recipient);
+ vars.initialRecipientBalance = FORK_TOKEN.balanceOf(params.recipient);
// Expect the relevant events to be emitted.
vm.expectEmit({ emitter: address(lockup) });
emit ISablierLockupBase.WithdrawFromLockupStream({
streamId: vars.streamId,
to: params.recipient,
- asset: FORK_ASSET,
+ token: FORK_TOKEN,
amount: params.withdrawAmount
});
vm.expectEmit({ emitter: address(lockup) });
@@ -300,8 +300,8 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
vars.expectedWithdrawnAmount = params.withdrawAmount;
assertEq(vars.actualWithdrawnAmount, vars.expectedWithdrawnAmount, "post-withdraw withdrawnAmount");
- // Load the post-withdraw asset balances.
- vars.balances = getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.recipient));
+ // Load the post-withdraw token balances.
+ vars.balances = getTokenBalances(address(FORK_TOKEN), Solarray.addresses(address(lockup), params.recipient));
vars.actualLockupBalance = vars.balances[0];
vars.actualRecipientBalance = vars.balances[1];
@@ -323,9 +323,9 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
// Only run the cancel tests if the stream is neither depleted nor settled.
if (!vars.isDepleted && !vars.isSettled) {
- // Load the pre-cancel asset balances.
+ // Load the pre-cancel token balances.
vars.balances = getTokenBalances(
- address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient)
+ address(FORK_TOKEN), Solarray.addresses(address(lockup), params.sender, params.recipient)
);
vars.initialLockupBalance = vars.balances[0];
vars.initialSenderBalance = vars.balances[1];
@@ -336,7 +336,7 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
vars.senderAmount = lockup.refundableAmountOf(vars.streamId);
vars.recipientAmount = lockup.withdrawableAmountOf(vars.streamId);
emit ISablierLockupBase.CancelLockupStream(
- vars.streamId, params.sender, params.recipient, FORK_ASSET, vars.senderAmount, vars.recipientAmount
+ vars.streamId, params.sender, params.recipient, FORK_TOKEN, vars.senderAmount, vars.recipientAmount
);
vm.expectEmit({ emitter: address(lockup) });
emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId });
@@ -350,9 +350,9 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test {
vars.expectedStatus = vars.recipientAmount > 0 ? Lockup.Status.CANCELED : Lockup.Status.DEPLETED;
assertEq(vars.actualStatus, vars.expectedStatus, "post-cancel stream status");
- // Load the post-cancel asset balances.
+ // Load the post-cancel token balances.
vars.balances = getTokenBalances(
- address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient)
+ address(FORK_TOKEN), Solarray.addresses(address(lockup), params.sender, params.recipient)
);
vars.actualLockupBalance = vars.balances[0];
vars.actualSenderBalance = vars.balances[1];
diff --git a/tests/fork/LockupLinear.t.sol b/tests/fork/LockupLinear.t.sol
index e77298381..8dd0cc328 100644
--- a/tests/fork/LockupLinear.t.sol
+++ b/tests/fork/LockupLinear.t.sol
@@ -15,7 +15,7 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
CONSTRUCTOR
//////////////////////////////////////////////////////////////////////////*/
- constructor(IERC20 forkAsset, address forkAssetHolder) Fork_Test(forkAsset, forkAssetHolder) { }
+ constructor(IERC20 forkToken, address forkTokenHolder) Fork_Test(forkToken, forkTokenHolder) { }
/*//////////////////////////////////////////////////////////////////////////
SET-UP FUNCTION
@@ -24,9 +24,9 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
function setUp() public virtual override {
Fork_Test.setUp();
- // Approve {SablierLockup} to transfer the asset holder's assets.
- // We use a low-level call to ignore reverts because the asset can have the missing return value bug.
- (bool success,) = address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockup), MAX_UINT256)));
+ // Approve {SablierLockup} to transfer the token holder's tokens.
+ // We use a low-level call to ignore reverts because the token can have the missing return value bug.
+ (bool success,) = address(FORK_TOKEN).call(abi.encodeCall(IERC20.approve, (address(lockup), MAX_UINT256)));
success;
}
@@ -149,15 +149,15 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
: 0;
// Make the holder the caller.
- resetPrank(FORK_ASSET_HOLDER);
+ resetPrank(FORK_TOKEN_HOLDER);
/*//////////////////////////////////////////////////////////////////////////
CREATE
//////////////////////////////////////////////////////////////////////////*/
- // Load the pre-create asset balances.
+ // Load the pre-create token balances.
vars.balances =
- getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.broker.account));
+ getTokenBalances(address(FORK_TOKEN), Solarray.addresses(address(lockup), params.broker.account));
vars.initialLockupBalance = vars.balances[0];
vars.initialBrokerBalance = vars.balances[1];
@@ -170,11 +170,11 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
emit ISablierLockup.CreateLockupLinearStream({
streamId: vars.streamId,
commonParams: Lockup.CreateEventCommon({
- funder: FORK_ASSET_HOLDER,
+ funder: FORK_TOKEN_HOLDER,
sender: params.sender,
recipient: params.recipient,
amounts: vars.createAmounts,
- asset: FORK_ASSET,
+ token: FORK_TOKEN,
cancelable: true,
transferable: true,
timestamps: params.timestamps,
@@ -191,7 +191,7 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
sender: params.sender,
recipient: params.recipient,
totalAmount: params.totalAmount,
- asset: FORK_ASSET,
+ token: FORK_TOKEN,
cancelable: true,
transferable: true,
timestamps: params.timestamps,
@@ -220,7 +220,7 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
vars.isCancelable = vars.isSettled ? false : true;
// Assert that the stream has been created.
- assertEq(lockup.getAsset(vars.streamId), FORK_ASSET, "asset");
+ assertEq(lockup.getToken(vars.streamId), FORK_TOKEN, "token");
assertEq(lockup.getCliffTime(vars.streamId), params.cliffTime, "cliffTime");
assertEq(lockup.getDepositedAmount(vars.streamId), vars.createAmounts.deposit, "depositedAmount");
assertEq(lockup.getEndTime(vars.streamId), params.timestamps.end, "endTime");
@@ -256,9 +256,9 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
vars.expectedNFTOwner = params.recipient;
assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-create NFT owner");
- // Load the post-create asset balances.
+ // Load the post-create token balances.
vars.balances = getTokenBalances(
- address(FORK_ASSET), Solarray.addresses(address(lockup), FORK_ASSET_HOLDER, params.broker.account)
+ address(FORK_TOKEN), Solarray.addresses(address(lockup), FORK_TOKEN_HOLDER, params.broker.account)
);
vars.actualLockupBalance = vars.balances[0];
vars.actualHolderBalance = vars.balances[1];
@@ -299,17 +299,17 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
// Only run the withdraw tests if the withdraw amount is not zero.
if (params.withdrawAmount > 0) {
- // Load the pre-withdraw asset balances.
+ // Load the pre-withdraw token balances.
vars.initialLockupBalance = vars.actualLockupBalance;
vars.initialLockupBalanceETH = address(lockup).balance;
- vars.initialRecipientBalance = FORK_ASSET.balanceOf(params.recipient);
+ vars.initialRecipientBalance = FORK_TOKEN.balanceOf(params.recipient);
// Expect the relevant events to be emitted.
vm.expectEmit({ emitter: address(lockup) });
emit ISablierLockupBase.WithdrawFromLockupStream({
streamId: vars.streamId,
to: params.recipient,
- asset: FORK_ASSET,
+ token: FORK_TOKEN,
amount: params.withdrawAmount
});
vm.expectEmit({ emitter: address(lockup) });
@@ -340,8 +340,8 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
vars.expectedWithdrawnAmount = params.withdrawAmount;
assertEq(vars.actualWithdrawnAmount, vars.expectedWithdrawnAmount, "post-withdraw withdrawnAmount");
- // Load the post-withdraw asset balances.
- vars.balances = getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.recipient));
+ // Load the post-withdraw token balances.
+ vars.balances = getTokenBalances(address(FORK_TOKEN), Solarray.addresses(address(lockup), params.recipient));
vars.actualLockupBalance = vars.balances[0];
vars.actualRecipientBalance = vars.balances[1];
@@ -363,9 +363,9 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
// Only run the cancel tests if the stream is neither depleted nor settled.
if (!vars.isDepleted && !vars.isSettled) {
- // Load the pre-cancel asset balances.
+ // Load the pre-cancel token balances.
vars.balances = getTokenBalances(
- address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient)
+ address(FORK_TOKEN), Solarray.addresses(address(lockup), params.sender, params.recipient)
);
vars.initialLockupBalance = vars.balances[0];
vars.initialSenderBalance = vars.balances[1];
@@ -376,7 +376,7 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
vars.senderAmount = lockup.refundableAmountOf(vars.streamId);
vars.recipientAmount = lockup.withdrawableAmountOf(vars.streamId);
emit ISablierLockupBase.CancelLockupStream(
- vars.streamId, params.sender, params.recipient, FORK_ASSET, vars.senderAmount, vars.recipientAmount
+ vars.streamId, params.sender, params.recipient, FORK_TOKEN, vars.senderAmount, vars.recipientAmount
);
vm.expectEmit({ emitter: address(lockup) });
emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId });
@@ -390,9 +390,9 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test {
vars.expectedStatus = vars.recipientAmount > 0 ? Lockup.Status.CANCELED : Lockup.Status.DEPLETED;
assertEq(vars.actualStatus, vars.expectedStatus, "post-cancel stream status");
- // Load the post-cancel asset balances.
+ // Load the post-cancel token balances.
vars.balances = getTokenBalances(
- address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient)
+ address(FORK_TOKEN), Solarray.addresses(address(lockup), params.sender, params.recipient)
);
vars.actualLockupBalance = vars.balances[0];
vars.actualSenderBalance = vars.balances[1];
diff --git a/tests/fork/LockupTranched.t.sol b/tests/fork/LockupTranched.t.sol
index a7d84c0bc..849e48bbb 100644
--- a/tests/fork/LockupTranched.t.sol
+++ b/tests/fork/LockupTranched.t.sol
@@ -14,7 +14,7 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
CONSTRUCTOR
//////////////////////////////////////////////////////////////////////////*/
- constructor(IERC20 forkAsset, address forkAssetHolder) Fork_Test(forkAsset, forkAssetHolder) { }
+ constructor(IERC20 forkToken, address forkTokenHolder) Fork_Test(forkToken, forkTokenHolder) { }
/*//////////////////////////////////////////////////////////////////////////
SET-UP FUNCTION
@@ -23,9 +23,9 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
function setUp() public virtual override {
Fork_Test.setUp();
- // Approve {SablierLockup} to transfer the holder's assets.
- // We use a low-level call to ignore reverts because the asset can have the missing return value bug.
- (bool success,) = address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockup), MAX_UINT256)));
+ // Approve {SablierLockup} to transfer the holder's tokens.
+ // We use a low-level call to ignore reverts because the token can have the missing return value bug.
+ (bool success,) = address(FORK_TOKEN).call(abi.encodeCall(IERC20.approve, (address(lockup), MAX_UINT256)));
success;
}
@@ -126,15 +126,15 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
});
// Make the holder the caller.
- resetPrank(FORK_ASSET_HOLDER);
+ resetPrank(FORK_TOKEN_HOLDER);
/*//////////////////////////////////////////////////////////////////////////
CREATE
//////////////////////////////////////////////////////////////////////////*/
- // Load the pre-create asset balances.
+ // Load the pre-create token balances.
vars.balances =
- getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.broker.account));
+ getTokenBalances(address(FORK_TOKEN), Solarray.addresses(address(lockup), params.broker.account));
vars.initialLockupBalance = vars.balances[0];
vars.initialBrokerBalance = vars.balances[1];
@@ -149,11 +149,11 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
emit ISablierLockup.CreateLockupTranchedStream({
streamId: vars.streamId,
commonParams: Lockup.CreateEventCommon({
- funder: FORK_ASSET_HOLDER,
+ funder: FORK_TOKEN_HOLDER,
sender: params.sender,
recipient: params.recipient,
amounts: vars.createAmounts,
- asset: FORK_ASSET,
+ token: FORK_TOKEN,
cancelable: true,
transferable: true,
timestamps: vars.timestamps,
@@ -169,7 +169,7 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
sender: params.sender,
recipient: params.recipient,
totalAmount: vars.totalAmount,
- asset: FORK_ASSET,
+ token: FORK_TOKEN,
cancelable: true,
transferable: true,
timestamps: vars.timestamps,
@@ -185,7 +185,7 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
vars.isCancelable = vars.isSettled ? false : true;
// Assert that the stream has been created.
- assertEq(lockup.getAsset(vars.streamId), FORK_ASSET, "asset");
+ assertEq(lockup.getToken(vars.streamId), FORK_TOKEN, "token");
assertEq(lockup.getDepositedAmount(vars.streamId), vars.createAmounts.deposit, "depositedAmount");
assertEq(lockup.getEndTime(vars.streamId), vars.timestamps.end, "endTime");
assertEq(lockup.isCancelable(vars.streamId), vars.isCancelable, "isCancelable");
@@ -219,9 +219,9 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
vars.expectedNFTOwner = params.recipient;
assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-create NFT owner");
- // Load the post-create asset balances.
+ // Load the post-create token balances.
vars.balances = getTokenBalances(
- address(FORK_ASSET), Solarray.addresses(address(lockup), FORK_ASSET_HOLDER, params.broker.account)
+ address(FORK_TOKEN), Solarray.addresses(address(lockup), FORK_TOKEN_HOLDER, params.broker.account)
);
vars.actualLockupBalance = vars.balances[0];
vars.actualHolderBalance = vars.balances[1];
@@ -259,17 +259,17 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
// Only run the withdraw tests if the withdraw amount is not zero.
if (params.withdrawAmount > 0) {
- // Load the pre-withdraw asset balances.
+ // Load the pre-withdraw token balances.
vars.initialLockupBalance = vars.actualLockupBalance;
vars.initialLockupBalanceETH = address(lockup).balance;
- vars.initialRecipientBalance = FORK_ASSET.balanceOf(params.recipient);
+ vars.initialRecipientBalance = FORK_TOKEN.balanceOf(params.recipient);
// Expect the relevant events to be emitted.
vm.expectEmit({ emitter: address(lockup) });
emit ISablierLockupBase.WithdrawFromLockupStream({
streamId: vars.streamId,
to: params.recipient,
- asset: FORK_ASSET,
+ token: FORK_TOKEN,
amount: params.withdrawAmount
});
vm.expectEmit({ emitter: address(lockup) });
@@ -300,8 +300,8 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
vars.expectedWithdrawnAmount = params.withdrawAmount;
assertEq(vars.actualWithdrawnAmount, vars.expectedWithdrawnAmount, "post-withdraw withdrawnAmount");
- // Load the post-withdraw asset balances.
- vars.balances = getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.recipient));
+ // Load the post-withdraw token balances.
+ vars.balances = getTokenBalances(address(FORK_TOKEN), Solarray.addresses(address(lockup), params.recipient));
vars.actualLockupBalance = vars.balances[0];
vars.actualRecipientBalance = vars.balances[1];
@@ -323,9 +323,9 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
// Only run the cancel tests if the stream is neither depleted nor settled.
if (!vars.isDepleted && !vars.isSettled) {
- // Load the pre-cancel asset balances.
+ // Load the pre-cancel token balances.
vars.balances = getTokenBalances(
- address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient)
+ address(FORK_TOKEN), Solarray.addresses(address(lockup), params.sender, params.recipient)
);
vars.initialLockupBalance = vars.balances[0];
vars.initialSenderBalance = vars.balances[1];
@@ -336,7 +336,7 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
vars.senderAmount = lockup.refundableAmountOf(vars.streamId);
vars.recipientAmount = lockup.withdrawableAmountOf(vars.streamId);
emit ISablierLockupBase.CancelLockupStream(
- vars.streamId, params.sender, params.recipient, FORK_ASSET, vars.senderAmount, vars.recipientAmount
+ vars.streamId, params.sender, params.recipient, FORK_TOKEN, vars.senderAmount, vars.recipientAmount
);
vm.expectEmit({ emitter: address(lockup) });
emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId });
@@ -350,9 +350,9 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test {
vars.expectedStatus = vars.recipientAmount > 0 ? Lockup.Status.CANCELED : Lockup.Status.DEPLETED;
assertEq(vars.actualStatus, vars.expectedStatus, "post-cancel stream status");
- // Load the post-cancel asset balances.
+ // Load the post-cancel token balances.
vars.balances = getTokenBalances(
- address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient)
+ address(FORK_TOKEN), Solarray.addresses(address(lockup), params.sender, params.recipient)
);
vars.actualLockupBalance = vars.balances[0];
vars.actualSenderBalance = vars.balances[1];
diff --git a/tests/fork/assets/DAI.t.sol b/tests/fork/tokens/DAI.t.sol
similarity index 65%
rename from tests/fork/assets/DAI.t.sol
rename to tests/fork/tokens/DAI.t.sol
index e96fd5b5b..075f223a1 100644
--- a/tests/fork/assets/DAI.t.sol
+++ b/tests/fork/tokens/DAI.t.sol
@@ -7,12 +7,12 @@ import { Lockup_Dynamic_Fork_Test } from "../LockupDynamic.t.sol";
import { Lockup_Linear_Fork_Test } from "../LockupLinear.t.sol";
import { Lockup_Tranched_Fork_Test } from "../LockupTranched.t.sol";
-/// @dev A typical 18-decimal ERC-20 asset with a normal total supply.
-IERC20 constant FORK_ASSET = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
-address constant FORK_ASSET_HOLDER = 0x66F62574ab04989737228D18C3624f7FC1edAe14;
+/// @dev A typical 18-decimal ERC-20 token with a normal total supply.
+IERC20 constant FORK_TOKEN = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
+address constant FORK_TOKEN_HOLDER = 0x66F62574ab04989737228D18C3624f7FC1edAe14;
-contract DAI_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract DAI_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
-contract DAI_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract DAI_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
-contract DAI_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract DAI_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
diff --git a/tests/fork/assets/EURS.t.sol b/tests/fork/tokens/EURS.t.sol
similarity index 67%
rename from tests/fork/assets/EURS.t.sol
rename to tests/fork/tokens/EURS.t.sol
index ea6dc8520..2502c8416 100644
--- a/tests/fork/assets/EURS.t.sol
+++ b/tests/fork/tokens/EURS.t.sol
@@ -7,12 +7,12 @@ import { Lockup_Dynamic_Fork_Test } from "../LockupDynamic.t.sol";
import { Lockup_Linear_Fork_Test } from "../LockupLinear.t.sol";
import { Lockup_Tranched_Fork_Test } from "../LockupTranched.t.sol";
-/// @dev An ERC-20 asset with 2 decimals.
-IERC20 constant FORK_ASSET = IERC20(0xdB25f211AB05b1c97D595516F45794528a807ad8);
-address constant FORK_ASSET_HOLDER = 0x1bee4F735062CD00841d6997964F187f5f5F5Ac9;
+/// @dev An ERC-20 token with 2 decimals.
+IERC20 constant FORK_TOKEN = IERC20(0xdB25f211AB05b1c97D595516F45794528a807ad8);
+address constant FORK_TOKEN_HOLDER = 0x1bee4F735062CD00841d6997964F187f5f5F5Ac9;
-contract EURS_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract EURS_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
-contract EURS_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract EURS_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
-contract EURS_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract EURS_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
diff --git a/tests/fork/assets/SHIB.t.sol b/tests/fork/tokens/SHIB.t.sol
similarity index 66%
rename from tests/fork/assets/SHIB.t.sol
rename to tests/fork/tokens/SHIB.t.sol
index 0f10927f1..3f6ea23d7 100644
--- a/tests/fork/assets/SHIB.t.sol
+++ b/tests/fork/tokens/SHIB.t.sol
@@ -7,12 +7,12 @@ import { Lockup_Dynamic_Fork_Test } from "../LockupDynamic.t.sol";
import { Lockup_Linear_Fork_Test } from "../LockupLinear.t.sol";
import { Lockup_Tranched_Fork_Test } from "../LockupTranched.t.sol";
-/// @dev An ERC-20 asset with a large total supply.
-IERC20 constant FORK_ASSET = IERC20(0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE);
-address constant FORK_ASSET_HOLDER = 0x73AF3bcf944a6559933396c1577B257e2054D935;
+/// @dev An ERC-20 token with a large total supply.
+IERC20 constant FORK_TOKEN = IERC20(0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE);
+address constant FORK_TOKEN_HOLDER = 0x73AF3bcf944a6559933396c1577B257e2054D935;
-contract SHIB_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract SHIB_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
-contract SHIB_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract SHIB_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
-contract SHIB_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract SHIB_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
diff --git a/tests/fork/assets/USDC.t.sol b/tests/fork/tokens/USDC.t.sol
similarity index 67%
rename from tests/fork/assets/USDC.t.sol
rename to tests/fork/tokens/USDC.t.sol
index dce918831..c166e0dc4 100644
--- a/tests/fork/assets/USDC.t.sol
+++ b/tests/fork/tokens/USDC.t.sol
@@ -7,12 +7,12 @@ import { Lockup_Dynamic_Fork_Test } from "../LockupDynamic.t.sol";
import { Lockup_Linear_Fork_Test } from "../LockupLinear.t.sol";
import { Lockup_Tranched_Fork_Test } from "../LockupTranched.t.sol";
-/// @dev An ERC-20 asset with 6 decimals.
-IERC20 constant FORK_ASSET = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
-address constant FORK_ASSET_HOLDER = 0x09528d637deb5857dc059dddE6316D465a8b3b69;
+/// @dev An ERC-20 token with 6 decimals.
+IERC20 constant FORK_TOKEN = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
+address constant FORK_TOKEN_HOLDER = 0x09528d637deb5857dc059dddE6316D465a8b3b69;
-contract USDC_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract USDC_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
-contract USDC_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract USDC_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
-contract USDC_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract USDC_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
diff --git a/tests/fork/assets/USDT.t.sol b/tests/fork/tokens/USDT.t.sol
similarity index 65%
rename from tests/fork/assets/USDT.t.sol
rename to tests/fork/tokens/USDT.t.sol
index 6bee0e6b1..4bae90eb8 100644
--- a/tests/fork/assets/USDT.t.sol
+++ b/tests/fork/tokens/USDT.t.sol
@@ -7,12 +7,12 @@ import { Lockup_Dynamic_Fork_Test } from "../LockupDynamic.t.sol";
import { Lockup_Linear_Fork_Test } from "../LockupLinear.t.sol";
import { Lockup_Tranched_Fork_Test } from "../LockupTranched.t.sol";
-/// @dev An ERC-20 asset that suffers from the missing return value bug.
-IERC20 constant FORK_ASSET = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7);
-address constant FORK_ASSET_HOLDER = 0xee5B5B923fFcE93A870B3104b7CA09c3db80047A;
+/// @dev An ERC-20 token that suffers from the missing return value bug.
+IERC20 constant FORK_TOKEN = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7);
+address constant FORK_TOKEN_HOLDER = 0xee5B5B923fFcE93A870B3104b7CA09c3db80047A;
-contract USDT_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract USDT_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
-contract USDT_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract USDT_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
-contract USDT_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { }
+contract USDT_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_TOKEN, FORK_TOKEN_HOLDER) { }
diff --git a/tests/integration/concrete/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol b/tests/integration/concrete/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol
index acc01c3e9..0da7fc786 100644
--- a/tests/integration/concrete/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol
+++ b/tests/integration/concrete/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol
@@ -14,7 +14,7 @@ contract CreateWithDurationsLD_Integration_Test is Integration_Test {
}
function test_WhenBatchSizeNotZero() external {
- // Asset flow: Sender → batchLockup → SablierLockup
+ // Token flow: Sender → batchLockup → SablierLockup
// Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract.
expectCallToTransferFrom({
from: users.sender,
diff --git a/tests/integration/concrete/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol b/tests/integration/concrete/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol
index 9c9fb203d..93dd78e7f 100644
--- a/tests/integration/concrete/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol
+++ b/tests/integration/concrete/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol
@@ -14,7 +14,7 @@ contract CreateWithDurationsLL_Integration_Test is Integration_Test {
}
function test_WhenBatchSizeNotZero() external {
- // Asset flow: Sender → batchLockup → SablierLockup
+ // Token flow: Sender → batchLockup → SablierLockup
// Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract.
expectCallToTransferFrom({
from: users.sender,
diff --git a/tests/integration/concrete/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol b/tests/integration/concrete/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol
index 8a4fa4cd8..5af1c72a0 100644
--- a/tests/integration/concrete/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol
+++ b/tests/integration/concrete/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol
@@ -14,7 +14,7 @@ contract CreateWithDurationsLT_Integration_Test is Integration_Test {
}
function test_WhenBatchSizeNotZero() external {
- // Asset flow: Sender → batchLockup → SablierLockup
+ // Token flow: Sender → batchLockup → SablierLockup
// Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract.
expectCallToTransferFrom({
from: users.sender,
diff --git a/tests/integration/concrete/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol b/tests/integration/concrete/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol
index 72142aa4e..a03d0c5b7 100644
--- a/tests/integration/concrete/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol
+++ b/tests/integration/concrete/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol
@@ -14,7 +14,7 @@ contract CreateWithTimestampsLD_Integration_Test is Integration_Test {
}
function test_WhenBatchSizeNotZero() external {
- // Asset flow: Sender → batchLockup → SablierLockup
+ // Token flow: Sender → batchLockup → SablierLockup
// Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract.
expectCallToTransferFrom({
from: users.sender,
diff --git a/tests/integration/concrete/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol b/tests/integration/concrete/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol
index 9437ff4ae..05ef622cf 100644
--- a/tests/integration/concrete/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol
+++ b/tests/integration/concrete/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol
@@ -14,7 +14,7 @@ contract CreateWithTimestampsLL_Integration_Test is Integration_Test {
}
function test_WhenBatchSizeNotZero() external {
- // Asset flow: Sender → batchLockup → SablierLockup
+ // Token flow: Sender → batchLockup → SablierLockup
// Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract.
expectCallToTransferFrom({
from: users.sender,
diff --git a/tests/integration/concrete/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol b/tests/integration/concrete/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol
index a83be0993..8cf557884 100644
--- a/tests/integration/concrete/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol
+++ b/tests/integration/concrete/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol
@@ -14,7 +14,7 @@ contract CreateWithTimestampsLT_Integration_Test is Integration_Test {
}
function test_WhenBatchSizeNotZero() external {
- // Asset flow: Sender → batchLockup → SablierLockup
+ // Token flow: Sender → batchLockup → SablierLockup
// Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract.
expectCallToTransferFrom({
from: users.sender,
diff --git a/tests/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol b/tests/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol
index 57c5f5379..92add76ae 100644
--- a/tests/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol
+++ b/tests/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol
@@ -106,7 +106,7 @@ contract CancelMultiple_Integration_Concrete_Test is Integration_Test {
streamId: streamIds[0],
sender: users.sender,
recipient: users.recipient,
- asset: dai,
+ token: dai,
senderAmount: senderAmount0,
recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount0
});
@@ -115,7 +115,7 @@ contract CancelMultiple_Integration_Concrete_Test is Integration_Test {
streamId: streamIds[1],
sender: users.sender,
recipient: users.recipient,
- asset: dai,
+ token: dai,
senderAmount: senderAmount1,
recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount1
});
diff --git a/tests/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.t.sol b/tests/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.t.sol
index bf402e88a..288dabcf0 100644
--- a/tests/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.t.sol
+++ b/tests/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.t.sol
@@ -133,7 +133,7 @@ abstract contract CreateWithTimestamps_Integration_Concrete_Test is Integration_
createDefaultStream();
}
- function test_RevertWhen_AssetNotContract()
+ function test_RevertWhen_TokenNotContract()
external
whenNoDelegateCall
whenShapeNameNotExceed32Bytes
@@ -144,7 +144,7 @@ abstract contract CreateWithTimestamps_Integration_Concrete_Test is Integration_
whenStartTimeNotZero
{
address nonContract = address(8128);
- _defaultParams.createWithTimestamps.asset = IERC20(nonContract);
+ _defaultParams.createWithTimestamps.token = IERC20(nonContract);
vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract));
createDefaultStream();
}
diff --git a/tests/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.tree b/tests/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.tree
index 95f987761..5aa9239e9 100644
--- a/tests/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.tree
+++ b/tests/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.tree
@@ -20,5 +20,5 @@ CreateWithTimestamps_Integration_Concrete_Test
├── when start time zero
│ └── it should revert
└── when start time not zero
- └── when asset not contract
+ └── when token not contract
└── it should revert
diff --git a/tests/integration/concrete/lockup-base/getters/getters.t.sol b/tests/integration/concrete/lockup-base/getters/getters.t.sol
index b094b7d7a..898798639 100644
--- a/tests/integration/concrete/lockup-base/getters/getters.t.sol
+++ b/tests/integration/concrete/lockup-base/getters/getters.t.sol
@@ -7,20 +7,6 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Integration_Test } from "../../../Integration.t.sol";
contract Getters_Integration_Concrete_Test is Integration_Test {
- /*//////////////////////////////////////////////////////////////////////////
- GET-ASSET
- //////////////////////////////////////////////////////////////////////////*/
-
- function test_GetAssetRevertGiven_Null() external {
- expectRevert_Null({ callData: abi.encodeCall(lockup.getAsset, nullStreamId) });
- }
-
- function test_GetAssetGivenNotNull() external view {
- IERC20 actualAsset = lockup.getAsset(defaultStreamId);
- IERC20 expectedAsset = dai;
- assertEq(actualAsset, expectedAsset, "asset");
- }
-
/*//////////////////////////////////////////////////////////////////////////
GET-DEPOSITED-AMOUNT
//////////////////////////////////////////////////////////////////////////*/
@@ -172,6 +158,20 @@ contract Getters_Integration_Concrete_Test is Integration_Test {
assertEq(actualStartTime, expectedStartTime, "startTime");
}
+ /*//////////////////////////////////////////////////////////////////////////
+ GET-TOKEN
+ //////////////////////////////////////////////////////////////////////////*/
+
+ function test_GetTokenRevertGiven_Null() external {
+ expectRevert_Null({ callData: abi.encodeCall(lockup.getToken, nullStreamId) });
+ }
+
+ function test_GetTokenGivenNotNull() external view {
+ IERC20 actualToken = lockup.getToken(defaultStreamId);
+ IERC20 expectedToken = dai;
+ assertEq(actualToken, expectedToken, "token");
+ }
+
/*//////////////////////////////////////////////////////////////////////////
GET-WITHDRAWN-AMOUNT
//////////////////////////////////////////////////////////////////////////*/
diff --git a/tests/integration/concrete/lockup-base/getters/getters.tree b/tests/integration/concrete/lockup-base/getters/getters.tree
index 38e902c9b..bd0e3918b 100644
--- a/tests/integration/concrete/lockup-base/getters/getters.tree
+++ b/tests/integration/concrete/lockup-base/getters/getters.tree
@@ -1,9 +1,3 @@
-Getters_Integration_Concrete_Test::getAsset
-├── given null
-│ └── it should revert
-└── given not null
- └── it should return the correct address of the asset
-
Getters_Integration_Concrete_Test::getDepositedAmount
├── given null
│ └── it should revert
@@ -55,6 +49,12 @@ Getters_Integration_Concrete_Test::getStartTime
└── given not null
└── it should return the correct start time
+Getters_Integration_Concrete_Test::getToken
+├── given null
+│ └── it should revert
+└── given not null
+ └── it should return the correct address of the token
+
Getters_Integration_Concrete_Test::getWithdrawnAmount
├── given null
│ └── it should revert
diff --git a/tests/integration/concrete/lockup-base/status-of/statusOf.t.sol b/tests/integration/concrete/lockup-base/status-of/statusOf.t.sol
index f54ed0828..499bc7a80 100644
--- a/tests/integration/concrete/lockup-base/status-of/statusOf.t.sol
+++ b/tests/integration/concrete/lockup-base/status-of/statusOf.t.sol
@@ -10,7 +10,7 @@ contract StatusOf_Integration_Concrete_Test is Integration_Test {
expectRevert_Null({ callData: abi.encodeCall(lockup.statusOf, nullStreamId) });
}
- function test_GivenAssetsFullyWithdrawn() external givenNotNull {
+ function test_GivenTokensFullyWithdrawn() external givenNotNull {
vm.warp({ newTimestamp: defaults.END_TIME() });
lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient });
@@ -20,7 +20,7 @@ contract StatusOf_Integration_Concrete_Test is Integration_Test {
assertEq(actualStatus, expectedStatus);
}
- function test_GivenCanceledStream() external givenNotNull givenAssetsNotFullyWithdrawn {
+ function test_GivenCanceledStream() external givenNotNull givenTokensNotFullyWithdrawn {
vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() });
lockup.cancel(defaultStreamId);
@@ -30,7 +30,7 @@ contract StatusOf_Integration_Concrete_Test is Integration_Test {
assertEq(actualStatus, expectedStatus);
}
- function test_GivenStartTimeInFuture() external givenNotNull givenAssetsNotFullyWithdrawn givenNotCanceledStream {
+ function test_GivenStartTimeInFuture() external givenNotNull givenTokensNotFullyWithdrawn givenNotCanceledStream {
vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds });
// It should return PENDING.
@@ -42,7 +42,7 @@ contract StatusOf_Integration_Concrete_Test is Integration_Test {
function test_GivenZeroRefundableAmount()
external
givenNotNull
- givenAssetsNotFullyWithdrawn
+ givenTokensNotFullyWithdrawn
givenNotCanceledStream
givenStartTimeNotInFuture
{
@@ -57,7 +57,7 @@ contract StatusOf_Integration_Concrete_Test is Integration_Test {
function test_GivenNonZeroRefundableAmount()
external
givenNotNull
- givenAssetsNotFullyWithdrawn
+ givenTokensNotFullyWithdrawn
givenNotCanceledStream
givenStartTimeNotInFuture
{
diff --git a/tests/integration/concrete/lockup-base/status-of/statusOf.tree b/tests/integration/concrete/lockup-base/status-of/statusOf.tree
index 03dcef072..0f9b5c56a 100644
--- a/tests/integration/concrete/lockup-base/status-of/statusOf.tree
+++ b/tests/integration/concrete/lockup-base/status-of/statusOf.tree
@@ -2,9 +2,9 @@ StatusOf_Integration_Concrete_Test
├── given null
│ └── it should revert
└── given not null
- ├── given assets fully withdrawn
+ ├── given tokens fully withdrawn
│ └── it should return DEPLETED
- └── given assets not fully withdrawn
+ └── given tokens not fully withdrawn
├── given canceled stream
│ └── it should return CANCELED
└── given not canceled stream
diff --git a/tests/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/tests/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol
index 0881ca580..8ec61ae93 100644
--- a/tests/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol
+++ b/tests/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol
@@ -57,7 +57,7 @@ contract WithdrawMaxAndTransfer_Integration_Concrete_Test is Integration_Test {
vm.warp({ newTimestamp: defaults.END_TIME() });
lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient });
- // It should not expect a transfer call on asset.
+ // It should not expect a transfer call on token.
vm.expectCall({ callee: address(dai), data: abi.encodeCall(IERC20.transfer, (users.recipient, 0)), count: 0 });
// It should emit {Transfer} event on NFT.
@@ -102,7 +102,7 @@ contract WithdrawMaxAndTransfer_Integration_Concrete_Test is Integration_Test {
// Get the withdraw amount.
uint128 expectedWithdrawnAmount = lockup.withdrawableAmountOf(defaultStreamId);
- // Expect the assets to be transferred to the Recipient.
+ // Expect the tokens to be transferred to the Recipient.
expectCallToTransfer({ to: users.recipient, value: expectedWithdrawnAmount });
// It should emit {Transfer} and {WithdrawFromLockupStream} events.
@@ -111,7 +111,7 @@ contract WithdrawMaxAndTransfer_Integration_Concrete_Test is Integration_Test {
streamId: defaultStreamId,
to: users.recipient,
amount: expectedWithdrawnAmount,
- asset: dai
+ token: dai
});
vm.expectEmit({ emitter: address(lockup) });
emit IERC721.Transfer({ from: users.recipient, to: users.alice, tokenId: defaultStreamId });
@@ -145,7 +145,7 @@ contract WithdrawMaxAndTransfer_Integration_Concrete_Test is Integration_Test {
// Get the withdraw amount.
uint128 expectedWithdrawnAmount = lockup.withdrawableAmountOf(defaultStreamId);
- // Expect the assets to be transferred to the Recipient.
+ // Expect the tokens to be transferred to the Recipient.
expectCallToTransfer({ to: users.recipient, value: expectedWithdrawnAmount });
// It should emit {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} events.
@@ -154,7 +154,7 @@ contract WithdrawMaxAndTransfer_Integration_Concrete_Test is Integration_Test {
streamId: defaultStreamId,
to: users.recipient,
amount: expectedWithdrawnAmount,
- asset: dai
+ token: dai
});
vm.expectEmit({ emitter: address(lockup) });
emit IERC4906.MetadataUpdate({ _tokenId: defaultStreamId });
diff --git a/tests/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree b/tests/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree
index 4fc64a99d..be72fe75d 100644
--- a/tests/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree
+++ b/tests/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree
@@ -12,7 +12,7 @@ WithdrawMaxAndTransfer_Integration_Concrete_Test
│ └── it should revert
└── given not burned NFT
├── given zero withdrawable amount
- │ ├── it should not expect a transfer call on asset
+ │ ├── it should not expect a transfer call on token
│ └── it should emit {Transfer} event on NFT
└── given non zero withdrawable amount
├── when caller not current recipient
diff --git a/tests/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol b/tests/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol
index 4757be1bd..c98b318dc 100644
--- a/tests/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol
+++ b/tests/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol
@@ -11,7 +11,7 @@ contract WithdrawMax_Integration_Concrete_Test is Integration_Test {
// Warp to the stream's end.
vm.warp({ newTimestamp: defaults.END_TIME() + 1 seconds });
- // Expect the ERC-20 assets to be transferred to the Recipient.
+ // Expect the ERC-20 tokens to be transferred to the Recipient.
expectCallToTransfer({ to: users.recipient, value: defaults.DEPOSIT_AMOUNT() });
// It should emit a {WithdrawFromLockupStream} event.
@@ -20,7 +20,7 @@ contract WithdrawMax_Integration_Concrete_Test is Integration_Test {
streamId: defaultStreamId,
to: users.recipient,
amount: defaults.DEPOSIT_AMOUNT(),
- asset: dai
+ token: dai
});
// Make the max withdrawal.
@@ -57,7 +57,7 @@ contract WithdrawMax_Integration_Concrete_Test is Integration_Test {
// Get the withdraw amount.
uint128 expectedWithdrawnAmount = lockup.withdrawableAmountOf(defaultStreamId);
- // Expect the assets to be transferred to the Recipient.
+ // Expect the tokens to be transferred to the Recipient.
expectCallToTransfer({ to: users.recipient, value: expectedWithdrawnAmount });
// It should emit a {WithdrawFromLockupStream} event.
@@ -66,7 +66,7 @@ contract WithdrawMax_Integration_Concrete_Test is Integration_Test {
streamId: defaultStreamId,
to: users.recipient,
amount: expectedWithdrawnAmount,
- asset: dai
+ token: dai
});
// Make the max withdrawal.
diff --git a/tests/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol b/tests/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol
index 2a00ccd30..fd800c8b7 100644
--- a/tests/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol
+++ b/tests/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol
@@ -206,21 +206,21 @@ contract WithdrawMultiple_Integration_Concrete_Test is Integration_Test {
emit ISablierLockupBase.WithdrawFromLockupStream({
streamId: withdrawMultipleStreamIds[0],
to: users.recipient,
- asset: dai,
+ token: dai,
amount: withdrawAmounts[0]
});
vm.expectEmit({ emitter: address(lockup) });
emit ISablierLockupBase.WithdrawFromLockupStream({
streamId: withdrawMultipleStreamIds[1],
to: users.recipient,
- asset: dai,
+ token: dai,
amount: withdrawAmounts[1]
});
vm.expectEmit({ emitter: address(lockup) });
emit ISablierLockupBase.WithdrawFromLockupStream({
streamId: withdrawMultipleStreamIds[2],
to: users.recipient,
- asset: dai,
+ token: dai,
amount: withdrawAmounts[2]
});
diff --git a/tests/integration/concrete/lockup-base/withdraw/withdraw.t.sol b/tests/integration/concrete/lockup-base/withdraw/withdraw.t.sol
index 1a2a800f0..b07f2cf1f 100644
--- a/tests/integration/concrete/lockup-base/withdraw/withdraw.t.sol
+++ b/tests/integration/concrete/lockup-base/withdraw/withdraw.t.sol
@@ -145,7 +145,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test {
emit ISablierLockupBase.WithdrawFromLockupStream({
streamId: defaultStreamId,
to: users.alice,
- asset: dai,
+ token: dai,
amount: withdrawAmount
});
vm.expectEmit({ emitter: address(lockup) });
@@ -264,7 +264,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test {
emit ISablierLockupBase.WithdrawFromLockupStream({
streamId: defaultStreamId,
to: users.recipient,
- asset: dai,
+ token: dai,
amount: withdrawAmount
});
vm.expectEmit({ emitter: address(lockup) });
@@ -456,7 +456,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test {
// Set the withdraw amount to the default amount.
uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT();
- // Expect the assets to be transferred to the recipient contract.
+ // Expect the tokens to be transferred to the recipient contract.
expectCallToTransfer({ to: address(recipientGood), value: withdrawAmount });
// It should make Sablier run the recipient hook.
@@ -473,7 +473,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test {
emit ISablierLockupBase.WithdrawFromLockupStream({
streamId: recipientGoodStreamId,
to: address(recipientGood),
- asset: dai,
+ token: dai,
amount: withdrawAmount
});
vm.expectEmit({ emitter: address(lockup) });
diff --git a/tests/integration/concrete/lockup-dynamic/create-with-durations-ld/createWithDurationsLD.t.sol b/tests/integration/concrete/lockup-dynamic/create-with-durations-ld/createWithDurationsLD.t.sol
index 1463eee53..bebc8b8c0 100644
--- a/tests/integration/concrete/lockup-dynamic/create-with-durations-ld/createWithDurationsLD.t.sol
+++ b/tests/integration/concrete/lockup-dynamic/create-with-durations-ld/createWithDurationsLD.t.sol
@@ -176,7 +176,7 @@ contract CreateWithDurationsLD_Integration_Concrete_Test is Lockup_Dynamic_Integ
assertTrue(lockup.isStream(streamId), "isStream");
assertTrue(lockup.isCancelable(streamId), "isCancelable");
assertTrue(lockup.isTransferable(streamId), "isTransferable");
- assertEq(lockup.getAsset(streamId), dai, "asset");
+ assertEq(lockup.getToken(streamId), dai, "token");
assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_DYNAMIC);
// Assert that the stream's status is "STREAMING".
diff --git a/tests/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.t.sol b/tests/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.t.sol
index e9e0eda1d..c042b2cf9 100644
--- a/tests/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.t.sol
+++ b/tests/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.t.sol
@@ -37,7 +37,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
{
LockupDynamic.Segment[] memory segments;
vm.expectRevert(Errors.SablierHelpers_SegmentCountZero.selector);
@@ -53,7 +53,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenSegmentCountNotZero
{
uint256 segmentCount = defaults.MAX_COUNT() + 1;
@@ -72,7 +72,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenSegmentCountNotZero
whenSegmentCountNotExceedMaxValue
{
@@ -92,7 +92,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenSegmentCountNotZero
whenSegmentCountNotExceedMaxValue
whenSegmentAmountsSumNotOverflow
@@ -121,7 +121,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenSegmentCountNotZero
whenSegmentCountNotExceedMaxValue
whenSegmentAmountsSumNotOverflow
@@ -150,7 +150,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenSegmentCountNotZero
whenSegmentCountNotExceedMaxValue
whenSegmentAmountsSumNotOverflow
@@ -209,7 +209,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
createDefaultStream();
}
- function test_WhenAssetMissesERC20ReturnValue()
+ function test_WhenTokenMissesERC20ReturnValue()
external
whenNoDelegateCall
whenShapeNameNotExceed32Bytes
@@ -218,7 +218,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenSegmentCountNotZero
whenSegmentCountNotExceedMaxValue
whenSegmentAmountsSumNotOverflow
@@ -229,7 +229,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
_testCreateWithTimestampsLD(address(usdt));
}
- function test_WhenAssetNotMissERC20ReturnValue()
+ function test_WhenTokenNotMissERC20ReturnValue()
external
whenNoDelegateCall
whenShapeNameNotExceed32Bytes
@@ -244,12 +244,12 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
whenTimestampsStrictlyIncreasing
whenDepositAmountNotEqualSegmentAmountsSum
whenBrokerFeeNotExceedMaxValue
- whenAssetContract
+ whenTokenContract
{
_testCreateWithTimestampsLD(address(dai));
}
- function _testCreateWithTimestampsLD(address asset) private {
+ function _testCreateWithTimestampsLD(address token) private {
// Make the Sender the stream's funder.
address funder = users.sender;
@@ -257,7 +257,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
// It should perform the ERC-20 transfers.
expectCallToTransferFrom({
- asset: IERC20(asset),
+ token: IERC20(token),
from: funder,
to: address(lockup),
value: defaults.DEPOSIT_AMOUNT()
@@ -265,7 +265,7 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
// Expect the broker fee to be paid to the broker.
expectCallToTransferFrom({
- asset: IERC20(asset),
+ token: IERC20(token),
from: funder,
to: users.broker,
value: defaults.BROKER_FEE_AMOUNT()
@@ -277,17 +277,17 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamp
vm.expectEmit({ emitter: address(lockup) });
emit ISablierLockup.CreateLockupDynamicStream({
streamId: expectedStreamId,
- commonParams: defaults.lockupCreateEvent(IERC20(asset)),
+ commonParams: defaults.lockupCreateEvent(IERC20(token)),
segments: defaults.segments()
});
// Create the stream.
- _defaultParams.createWithTimestamps.asset = IERC20(asset);
+ _defaultParams.createWithTimestamps.token = IERC20(token);
uint256 streamId = createDefaultStream();
// It should create the stream.
assertEqStream(streamId);
- assertEq(lockup.getAsset(streamId), IERC20(asset), "asset");
+ assertEq(lockup.getToken(streamId), IERC20(token), "token");
assertEq(lockup.getSegments(streamId), defaults.segments());
assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_DYNAMIC);
}
diff --git a/tests/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.tree b/tests/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.tree
index 997b2e331..9f98db7b2 100644
--- a/tests/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.tree
+++ b/tests/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.tree
@@ -1,5 +1,5 @@
CreateWithTimestampsLD_Integration_Concrete_Test
-└── when asset contract
+└── when token contract
├── when segment count zero
│ └── it should revert
└── when segment count not zero
@@ -20,13 +20,13 @@ CreateWithTimestampsLD_Integration_Concrete_Test
├── when deposit amount not equal segment amounts sum
│ └── it should revert
└── when deposit amount equals segment amounts sum
- ├── when asset misses ERC20 return value
+ ├── when token misses ERC20 return value
│ ├── it should create the stream
│ ├── it should bump the next stream ID
│ ├── it should mint the NFT
│ ├── it should emit {CreateLockupDynamicStream} and {MetadataUpdate} events
│ └── it should perform the ERC-20 transfers
- └── when asset not miss ERC20 return value
+ └── when token not miss ERC20 return value
├── it should create the stream
├── it should bump the next stream ID
├── it should mint the NFT
diff --git a/tests/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol b/tests/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol
index e728e160b..e92b1ac82 100644
--- a/tests/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol
+++ b/tests/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol
@@ -12,7 +12,7 @@ import { Integration_Test } from "tests/integration/Integration.t.sol";
/// @dev Requirements for these tests to work:
/// - The stream ID must be 1
/// - The stream's sender must be `0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca`, i.e. `makeAddr("Sender")`
-/// - The stream asset must have the DAI symbol
+/// - The stream token must have the DAI symbol
/// - The contract deployer, i.e. the `sender` config option in `foundry.toml`, must have the default value
/// 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 so that the deployed contracts have the same addresses as
/// the values hard coded in the tests below
@@ -43,7 +43,7 @@ contract TokenURI_Lockup_Dynamic_Integration_Concrete_Test is Integration_Test {
tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" });
string memory actualDecodedTokenURI = string(Base64.decode(tokenURI));
string memory expectedDecodedTokenURI =
- unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier Lockup Dynamic contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Dynamic Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier Lockup Dynamic #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}';
+ unicode'{"attributes":[{"trait_type":"Token","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier Lockup Dynamic contract. The owner of this NFT can withdraw the streamed tokens, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Dynamic Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier Lockup Dynamic #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}';
assertEq(actualDecodedTokenURI, expectedDecodedTokenURI, "decoded token URI");
}
diff --git a/tests/integration/concrete/lockup-linear/create-with-durations-ll/createWithDurationsLL.t.sol b/tests/integration/concrete/lockup-linear/create-with-durations-ll/createWithDurationsLL.t.sol
index 69084ea91..8bc6726f1 100644
--- a/tests/integration/concrete/lockup-linear/create-with-durations-ll/createWithDurationsLL.t.sol
+++ b/tests/integration/concrete/lockup-linear/create-with-durations-ll/createWithDurationsLL.t.sol
@@ -103,7 +103,7 @@ contract CreateWithDurationsLL_Integration_Concrete_Test is Lockup_Linear_Integr
uint256 streamId = createDefaultStreamWithDurations();
// It should create the stream.
- assertEq(lockup.getAsset(streamId), dai, "asset");
+ assertEq(lockup.getToken(streamId), dai, "token");
assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime");
assertEq(lockup.isCancelable(streamId), true, "isCancelable");
assertFalse(lockup.isDepleted(streamId), "isDepleted");
diff --git a/tests/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.t.sol b/tests/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.t.sol
index 08c793d11..648fd994b 100644
--- a/tests/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.t.sol
+++ b/tests/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.t.sol
@@ -28,7 +28,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenCliffTimeZero
{
_defaultParams.cliffTime = 0;
@@ -49,7 +49,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenCliffTimeZero
{
uint40 startTime = defaults.END_TIME();
@@ -74,7 +74,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenCliffTimeZero
{
uint40 cliffTime = 0;
@@ -90,7 +90,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenCliffTimeNotZero
{
uint40 startTime = defaults.CLIFF_TIME();
@@ -116,7 +116,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenCliffTimeNotZero
whenStartTimeLessThanCliffTime
{
@@ -141,7 +141,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenCliffTimeNotZero
whenStartTimeLessThanCliffTime
whenCliffTimeLessThanEndTime
@@ -158,7 +158,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
createDefaultStream();
}
- function test_WhenAssetMissesERC20ReturnValue()
+ function test_WhenTokenMissesERC20ReturnValue()
external
whenNoDelegateCall
whenShapeNameNotExceed32Bytes
@@ -167,7 +167,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenCliffTimeNotZero
whenStartTimeLessThanCliffTime
whenCliffTimeLessThanEndTime
@@ -176,7 +176,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
_testCreateWithTimestampsLL(address(usdt), _defaultParams.cliffTime);
}
- function test_WhenAssetNotMissERC20ReturnValue()
+ function test_WhenTokenNotMissERC20ReturnValue()
external
whenNoDelegateCall
whenShapeNameNotExceed32Bytes
@@ -185,7 +185,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenCliffTimeNotZero
whenStartTimeLessThanCliffTime
whenCliffTimeLessThanEndTime
@@ -194,21 +194,21 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
_testCreateWithTimestampsLL(address(dai), _defaultParams.cliffTime);
}
- /// @dev Shared logic between {test_WhenStartTimeLessThanEndTime}, {test_WhenAssetMissesERC20ReturnValue} and
- /// {test_WhenAssetNotMissERC20ReturnValue}.
- function _testCreateWithTimestampsLL(address asset, uint40 cliffTime) private {
+ /// @dev Shared logic between {test_WhenStartTimeLessThanEndTime}, {test_WhenTokenMissesERC20ReturnValue} and
+ /// {test_WhenTokenNotMissERC20ReturnValue}.
+ function _testCreateWithTimestampsLL(address token, uint40 cliffTime) private {
// Make the Sender the stream's funder.
address funder = users.sender;
uint256 expectedStreamId = lockup.nextStreamId();
// Set the default parameters.
- _defaultParams.createWithTimestamps.asset = IERC20(asset);
+ _defaultParams.createWithTimestamps.token = IERC20(token);
_defaultParams.unlockAmounts.cliff = cliffTime == 0 ? 0 : _defaultParams.unlockAmounts.cliff;
_defaultParams.cliffTime = cliffTime;
// It should perform the ERC-20 transfers.
expectCallToTransferFrom({
- asset: IERC20(asset),
+ token: IERC20(token),
from: funder,
to: address(lockup),
value: defaults.DEPOSIT_AMOUNT()
@@ -216,7 +216,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
// Expect the broker fee to be paid to the broker.
expectCallToTransferFrom({
- asset: IERC20(asset),
+ token: IERC20(token),
from: funder,
to: users.broker,
value: defaults.BROKER_FEE_AMOUNT()
@@ -228,7 +228,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
vm.expectEmit({ emitter: address(lockup) });
emit ISablierLockup.CreateLockupLinearStream({
streamId: expectedStreamId,
- commonParams: defaults.lockupCreateEvent(IERC20(asset)),
+ commonParams: defaults.lockupCreateEvent(IERC20(token)),
cliffTime: cliffTime,
unlockAmounts: _defaultParams.unlockAmounts
});
@@ -238,7 +238,7 @@ contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamp
// It should create the stream.
assertEqStream(streamId);
- assertEq(lockup.getAsset(streamId), IERC20(asset), "asset");
+ assertEq(lockup.getToken(streamId), IERC20(token), "token");
assertEq(lockup.getCliffTime(streamId), cliffTime, "cliffTime");
assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_LINEAR);
assertEq(lockup.getUnlockAmounts(streamId).start, _defaultParams.unlockAmounts.start, "unlockAmounts.start");
diff --git a/tests/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.tree b/tests/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.tree
index f0b9dcafc..a2f021ad6 100644
--- a/tests/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.tree
+++ b/tests/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.tree
@@ -1,5 +1,5 @@
CreateWithTimestampsLL_Integration_Concrete_Test
-└── when asset contract
+└── when token contract
├── when cliff time zero
│ ├── when cliff unlock amount not zero
│ │ └── it should revert
@@ -17,13 +17,13 @@ CreateWithTimestampsLL_Integration_Concrete_Test
├── when unlock amounts sum exceeds deposit amount
│ └── it should revert
└── when unlock amounts sum not exceed deposit amount
- ├── when asset misses ERC20 return value
+ ├── when token misses ERC20 return value
│ ├── it should create the stream
│ ├── it should bump the next stream ID
│ ├── it should mint the NFT
│ ├── it should emit {MetadataUpdate} and {CreateLockupLinearStream} events
│ └── it should perform the ERC-20 transfers
- └── when asset not miss ERC20 return value
+ └── when token not miss ERC20 return value
├── it should create the stream
├── it should bump the next stream ID
├── it should mint the NFT
diff --git a/tests/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol b/tests/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol
index 3bb005ba1..834c1d610 100644
--- a/tests/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol
+++ b/tests/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol
@@ -12,7 +12,7 @@ import { Integration_Test } from "../LockupLinear.t.sol";
/// @dev Requirements for these tests to work:
/// - The stream ID must be 1
/// - The stream's sender must be `0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca`, i.e. `makeAddr("Sender")`
-/// - The stream asset must have the DAI symbol
+/// - The stream token must have the DAI symbol
/// - The contract deployer, i.e. the `sender` config option in `foundry.toml`, must have the default value
/// 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 so that the deployed contracts have the same addresses as
/// the values hard coded in the tests below
@@ -43,7 +43,7 @@ contract TokenURI_Lockup_Linear_Integration_Concrete_Test is Integration_Test {
tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" });
string memory actualDecodedTokenURI = string(Base64.decode(tokenURI));
string memory expectedDecodedTokenURI =
- unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier Lockup Linear contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Linear Address: 0x3381cd18e2fb4db236bf0525938ab6e43db0440f\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier Lockup Linear #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDE5LDIyJSw2MyUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCgxOSwyMiUsNjMlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMTksMjIlLDYzJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDE5LDIyJSw2MyUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woMTksMjIlLDYzJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgzMzgxY2QxOGUyZmI0ZGIyMzZiZjA1MjU5MzhhYjZlNDNkYjA0NDBmIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBMaW5lYXI8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iMCUiIGhyZWY9IiNGbG9hdGluZ1RleHQiIGZpbGw9IiNmZmYiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZmlsbC1vcGFjaXR5PSIuOCIgZm9udC1zaXplPSIyNnB4Ij48YW5pbWF0ZSBhZGRpdGl2ZT0ic3VtIiBhdHRyaWJ1dGVOYW1lPSJzdGFydE9mZnNldCIgYmVnaW49IjBzIiBkdXI9IjUwcyIgZnJvbT0iMCUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB0bz0iMTAwJSIvPjB4MzM4MWNkMThlMmZiNGRiMjM2YmYwNTI1OTM4YWI2ZTQzZGIwNDQwZiDigKIgU2FibGllciBWMiBMb2NrdXAgTGluZWFyPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9Ii01MCUiIGhyZWY9IiNGbG9hdGluZ1RleHQiIGZpbGw9IiNmZmYiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZmlsbC1vcGFjaXR5PSIuOCIgZm9udC1zaXplPSIyNnB4Ij48YW5pbWF0ZSBhZGRpdGl2ZT0ic3VtIiBhdHRyaWJ1dGVOYW1lPSJzdGFydE9mZnNldCIgYmVnaW49IjBzIiBkdXI9IjUwcyIgZnJvbT0iMCUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB0bz0iMTAwJSIvPjB4MDNhNmE4NGNkNzYyZDk3MDdhMjE2MDViNTQ4YWFhYjg5MTU2MmFhYiDigKIgREFJPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjwvdGV4dD48dXNlIGhyZWY9IiNHbG93IiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjR2xvdyIgeD0iMTAwMCIgeT0iMTAwMCIgZmlsbC1vcGFjaXR5PSIuOSIvPjx1c2UgaHJlZj0iI0xvZ28iIHg9IjE3MCIgeT0iMTcwIiB0cmFuc2Zvcm09InNjYWxlKC42KSIvPjx1c2UgaHJlZj0iI0hvdXJnbGFzcyIgeD0iMTUwIiB5PSI5MCIgdHJhbnNmb3JtPSJyb3RhdGUoMTApIiB0cmFuc2Zvcm0tb3JpZ2luPSI1MDAgNTAwIi8+PHVzZSBocmVmPSIjUHJvZ3Jlc3MiIHg9IjE0NCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjU3RhdHVzIiB4PSIzNjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0Ftb3VudCIgeD0iNTY4IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNEdXJhdGlvbiIgeD0iNzA0IiB5PSI3OTAiLz48L3N2Zz4="}';
+ unicode'{"attributes":[{"trait_type":"Token","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier Lockup Linear contract. The owner of this NFT can withdraw the streamed tokens, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Linear Address: 0x3381cd18e2fb4db236bf0525938ab6e43db0440f\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier Lockup Linear #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDE5LDIyJSw2MyUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCgxOSwyMiUsNjMlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMTksMjIlLDYzJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDE5LDIyJSw2MyUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woMTksMjIlLDYzJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgzMzgxY2QxOGUyZmI0ZGIyMzZiZjA1MjU5MzhhYjZlNDNkYjA0NDBmIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBMaW5lYXI8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iMCUiIGhyZWY9IiNGbG9hdGluZ1RleHQiIGZpbGw9IiNmZmYiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZmlsbC1vcGFjaXR5PSIuOCIgZm9udC1zaXplPSIyNnB4Ij48YW5pbWF0ZSBhZGRpdGl2ZT0ic3VtIiBhdHRyaWJ1dGVOYW1lPSJzdGFydE9mZnNldCIgYmVnaW49IjBzIiBkdXI9IjUwcyIgZnJvbT0iMCUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB0bz0iMTAwJSIvPjB4MzM4MWNkMThlMmZiNGRiMjM2YmYwNTI1OTM4YWI2ZTQzZGIwNDQwZiDigKIgU2FibGllciBWMiBMb2NrdXAgTGluZWFyPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9Ii01MCUiIGhyZWY9IiNGbG9hdGluZ1RleHQiIGZpbGw9IiNmZmYiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZmlsbC1vcGFjaXR5PSIuOCIgZm9udC1zaXplPSIyNnB4Ij48YW5pbWF0ZSBhZGRpdGl2ZT0ic3VtIiBhdHRyaWJ1dGVOYW1lPSJzdGFydE9mZnNldCIgYmVnaW49IjBzIiBkdXI9IjUwcyIgZnJvbT0iMCUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB0bz0iMTAwJSIvPjB4MDNhNmE4NGNkNzYyZDk3MDdhMjE2MDViNTQ4YWFhYjg5MTU2MmFhYiDigKIgREFJPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjwvdGV4dD48dXNlIGhyZWY9IiNHbG93IiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjR2xvdyIgeD0iMTAwMCIgeT0iMTAwMCIgZmlsbC1vcGFjaXR5PSIuOSIvPjx1c2UgaHJlZj0iI0xvZ28iIHg9IjE3MCIgeT0iMTcwIiB0cmFuc2Zvcm09InNjYWxlKC42KSIvPjx1c2UgaHJlZj0iI0hvdXJnbGFzcyIgeD0iMTUwIiB5PSI5MCIgdHJhbnNmb3JtPSJyb3RhdGUoMTApIiB0cmFuc2Zvcm0tb3JpZ2luPSI1MDAgNTAwIi8+PHVzZSBocmVmPSIjUHJvZ3Jlc3MiIHg9IjE0NCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjU3RhdHVzIiB4PSIzNjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0Ftb3VudCIgeD0iNTY4IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNEdXJhdGlvbiIgeD0iNzA0IiB5PSI3OTAiLz48L3N2Zz4="}';
assertEq(actualDecodedTokenURI, expectedDecodedTokenURI, "decoded token URI");
}
diff --git a/tests/integration/concrete/lockup-tranched/create-with-durations-lt/createWithDurationsLT.t.sol b/tests/integration/concrete/lockup-tranched/create-with-durations-lt/createWithDurationsLT.t.sol
index 5c92cd2ba..79abec6e0 100644
--- a/tests/integration/concrete/lockup-tranched/create-with-durations-lt/createWithDurationsLT.t.sol
+++ b/tests/integration/concrete/lockup-tranched/create-with-durations-lt/createWithDurationsLT.t.sol
@@ -159,7 +159,7 @@ contract CreateWithDurationsLT_Integration_Concrete_Test is Lockup_Tranched_Inte
// Assert that the stream has been created.
assertEq(lockup.getDepositedAmount(streamId), defaults.DEPOSIT_AMOUNT(), "depositedAmount");
- assertEq(lockup.getAsset(streamId), dai, "asset");
+ assertEq(lockup.getToken(streamId), dai, "token");
assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime");
assertEq(lockup.isCancelable(streamId), true, "isCancelable");
assertFalse(lockup.isDepleted(streamId), "isDepleted");
diff --git a/tests/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.t.sol b/tests/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.t.sol
index 908879b4f..9f215fbf7 100644
--- a/tests/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.t.sol
+++ b/tests/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.t.sol
@@ -43,7 +43,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenTrancheCountNotZero
{
uint256 trancheCount = defaults.MAX_COUNT() + 1;
@@ -61,7 +61,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenTrancheCountNotZero
whenTrancheCountNotExceedMaxValue
{
@@ -80,7 +80,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenTrancheCountNotZero
whenTrancheCountNotExceedMaxValue
whenTrancheAmountsSumNotOverflow
@@ -111,7 +111,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenTrancheCountNotZero
whenTrancheCountNotExceedMaxValue
whenTrancheAmountsSumNotOverflow
@@ -139,7 +139,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenTrancheCountNotZero
whenTrancheCountNotExceedMaxValue
whenTrancheAmountsSumNotOverflow
@@ -173,7 +173,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenTrancheCountNotZero
whenTrancheCountNotExceedMaxValue
whenTrancheAmountsSumNotOverflow
@@ -199,7 +199,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
createDefaultStream();
}
- function test_WhenAssetMissesERC20ReturnValue()
+ function test_WhenTokenMissesERC20ReturnValue()
external
whenNoDelegateCall
whenShapeNameNotExceed32Bytes
@@ -208,7 +208,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenTrancheCountNotZero
whenTrancheCountNotExceedMaxValue
whenTrancheAmountsSumNotOverflow
@@ -219,7 +219,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
_testCreateWithTimestampsLT(address(usdt));
}
- function test_WhenAssetNotMissERC20ReturnValue()
+ function test_WhenTokenNotMissERC20ReturnValue()
external
whenNoDelegateCall
whenShapeNameNotExceed32Bytes
@@ -228,7 +228,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
whenRecipientNotZeroAddress
whenDepositAmountNotZero
whenStartTimeNotZero
- whenAssetContract
+ whenTokenContract
whenTrancheCountNotZero
whenTrancheCountNotExceedMaxValue
whenTrancheAmountsSumNotOverflow
@@ -239,15 +239,15 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
_testCreateWithTimestampsLT(address(dai));
}
- /// @dev Shared logic between {test_CreateWithTimestamps_AssetMissingReturnValue} and {test_CreateWithTimestamps}.
- function _testCreateWithTimestampsLT(address asset) internal {
+ /// @dev Shared logic between {test_CreateWithTimestamps_TokenMissingReturnValue} and {test_CreateWithTimestamps}.
+ function _testCreateWithTimestampsLT(address token) internal {
// Make the Sender the stream's funder.
address funder = users.sender;
uint256 expectedStreamId = lockup.nextStreamId();
// It should perform the ERC-20 transfers.
expectCallToTransferFrom({
- asset: IERC20(asset),
+ token: IERC20(token),
from: funder,
to: address(lockup),
value: defaults.DEPOSIT_AMOUNT()
@@ -255,7 +255,7 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
// Expect the broker fee to be paid to the broker.
expectCallToTransferFrom({
- asset: IERC20(asset),
+ token: IERC20(token),
from: funder,
to: users.broker,
value: defaults.BROKER_FEE_AMOUNT()
@@ -267,17 +267,17 @@ contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamp
vm.expectEmit({ emitter: address(lockup) });
emit ISablierLockup.CreateLockupTranchedStream({
streamId: expectedStreamId,
- commonParams: defaults.lockupCreateEvent(IERC20(asset)),
+ commonParams: defaults.lockupCreateEvent(IERC20(token)),
tranches: defaults.tranches()
});
// It should create the stream.
- _defaultParams.createWithTimestamps.asset = IERC20(asset);
+ _defaultParams.createWithTimestamps.token = IERC20(token);
uint256 streamId = createDefaultStream();
// It should create the stream.
assertEqStream(streamId);
- assertEq(lockup.getAsset(streamId), IERC20(asset), "asset");
+ assertEq(lockup.getToken(streamId), IERC20(token), "token");
assertEq(lockup.getTranches(streamId), defaults.tranches());
assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_TRANCHED);
}
diff --git a/tests/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.tree b/tests/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.tree
index 950c52191..4fc1f102b 100644
--- a/tests/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.tree
+++ b/tests/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.tree
@@ -1,5 +1,5 @@
CreateWithTimestampsLT_Integration_Concrete_Test
-└── when asset contract
+└── when token contract
├── when tranche count zero
│ └── it should revert
└── when tranche count not zero
@@ -20,13 +20,13 @@ CreateWithTimestampsLT_Integration_Concrete_Test
├── when deposit amount not equal tranche amounts sum
│ └── it should revert
└── when deposit amount equals tranche amounts sum
- ├── when asset misses ERC20 return value
+ ├── when token misses ERC20 return value
│ ├── it should create the stream
│ ├── it should bump the next stream ID
│ ├── it should mint the NFT
│ ├── it should emit {CreateLockupTranchedStream} and {MetadataUpdate} events
│ └── it should perform the ERC-20 transfers
- └── when asset not miss ERC20 return value
+ └── when token not miss ERC20 return value
├── it should create the stream
├── it should bump the next stream ID
├── it should mint the NFT
diff --git a/tests/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol b/tests/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol
index 06f85eb0a..eef12008b 100644
--- a/tests/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol
+++ b/tests/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol
@@ -12,7 +12,7 @@ import { Integration_Test } from "../LockupTranched.t.sol";
/// @dev Requirements for these tests to work:
/// - The stream ID must be 1
/// - The stream's sender must be `0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca`, i.e. `makeAddr("Sender")`
-/// - The stream asset must have the DAI symbol
+/// - The stream token must have the DAI symbol
/// - The contract deployer, i.e. the `sender` config option in `foundry.toml`, must have the default value
/// 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 so that the deployed contracts have the same addresses as
/// the values hard coded in the tests below
@@ -43,7 +43,7 @@ contract TokenURI_Lockup_Tranched_Integration_Concrete_Test is Integration_Test
tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" });
string memory actualDecodedTokenURI = string(Base64.decode(tokenURI));
string memory expectedDecodedTokenURI =
- unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier Lockup Tranched contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Tranched Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier Lockup Tranched #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}';
+ unicode'{"attributes":[{"trait_type":"Token","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier Lockup Tranched contract. The owner of this NFT can withdraw the streamed tokens, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Tranched Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier Lockup Tranched #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}';
assertEq(actualDecodedTokenURI, expectedDecodedTokenURI, "decoded token URI");
}
diff --git a/tests/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol b/tests/integration/concrete/nft-descriptor/safe-token-decimals/safeTokenDecimals.t.sol
similarity index 60%
rename from tests/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol
rename to tests/integration/concrete/nft-descriptor/safe-token-decimals/safeTokenDecimals.t.sol
index 2955c3008..7e4fd2d03 100644
--- a/tests/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol
+++ b/tests/integration/concrete/nft-descriptor/safe-token-decimals/safeTokenDecimals.t.sol
@@ -3,22 +3,22 @@ pragma solidity >=0.8.22 <0.9.0;
import { Base_Test } from "tests/Base.t.sol";
-contract SafeAssetDecimals_Integration_Concrete_Test is Base_Test {
- function test_WhenAssetNotContract() external view {
+contract SafeTokenDecimals_Integration_Concrete_Test is Base_Test {
+ function test_WhenTokenNotContract() external view {
address eoa = vm.addr({ privateKey: 1 });
- uint8 actualDecimals = nftDescriptorMock.safeAssetDecimals_(address(eoa));
+ uint8 actualDecimals = nftDescriptorMock.safeTokenDecimals_(address(eoa));
uint8 expectedDecimals = 0;
assertEq(actualDecimals, expectedDecimals, "decimals");
}
- function test_WhenDecimalsNotImplemented() external view whenAssetContract {
- uint8 actualDecimals = nftDescriptorMock.safeAssetDecimals_(address(noop));
+ function test_WhenDecimalsNotImplemented() external view whenTokenContract {
+ uint8 actualDecimals = nftDescriptorMock.safeTokenDecimals_(address(noop));
uint8 expectedDecimals = 0;
assertEq(actualDecimals, expectedDecimals, "decimals");
}
- function test_WhenDecimalsImplemented() external view whenAssetContract {
- uint8 actualDecimals = nftDescriptorMock.safeAssetDecimals_(address(dai));
+ function test_WhenDecimalsImplemented() external view whenTokenContract {
+ uint8 actualDecimals = nftDescriptorMock.safeTokenDecimals_(address(dai));
uint8 expectedDecimals = dai.decimals();
assertEq(actualDecimals, expectedDecimals, "decimals");
}
diff --git a/tests/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.tree b/tests/integration/concrete/nft-descriptor/safe-token-decimals/safeTokenDecimals.tree
similarity index 66%
rename from tests/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.tree
rename to tests/integration/concrete/nft-descriptor/safe-token-decimals/safeTokenDecimals.tree
index b1515423b..6cd270a57 100644
--- a/tests/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.tree
+++ b/tests/integration/concrete/nft-descriptor/safe-token-decimals/safeTokenDecimals.tree
@@ -1,7 +1,7 @@
-SafeAssetDecimals_Integration_Concrete_Test
-├── when asset not contract
+SafeTokenDecimals_Integration_Concrete_Test
+├── when token not contract
│ └── it should return 0
-└── when asset contract
+└── when token contract
├── when decimals not implemented
│ └── it should return 0
└── when decimals implemented
diff --git a/tests/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol b/tests/integration/concrete/nft-descriptor/safe-token-symbol/safeTokenSymbol.t.sol
similarity index 67%
rename from tests/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol
rename to tests/integration/concrete/nft-descriptor/safe-token-symbol/safeTokenSymbol.t.sol
index b76d97007..c782d95cc 100644
--- a/tests/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol
+++ b/tests/integration/concrete/nft-descriptor/safe-token-symbol/safeTokenSymbol.t.sol
@@ -5,51 +5,51 @@ import { Base_Test } from "tests/Base.t.sol";
import { ERC20Bytes32 } from "tests/mocks/erc20/ERC20Bytes32.sol";
import { ERC20Mock } from "tests/mocks/erc20/ERC20Mock.sol";
-contract SafeAssetSymbol_Integration_Concrete_Test is Base_Test {
- function test_WhenAssetNotContract() external view {
+contract SafeTokenSymbol_Integration_Concrete_Test is Base_Test {
+ function test_WhenTokenNotContract() external view {
address eoa = vm.addr({ privateKey: 1 });
- string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(eoa));
+ string memory actualSymbol = nftDescriptorMock.safeTokenSymbol_(address(eoa));
string memory expectedSymbol = "ERC20";
assertEq(actualSymbol, expectedSymbol, "symbol");
}
- function test_GivenSymbolNotImplemented() external view whenAssetContract {
- string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(noop));
+ function test_GivenSymbolNotImplemented() external view whenTokenContract {
+ string memory actualSymbol = nftDescriptorMock.safeTokenSymbol_(address(noop));
string memory expectedSymbol = "ERC20";
assertEq(actualSymbol, expectedSymbol, "symbol");
}
- function test_GivenSymbolAsBytes32() external whenAssetContract givenSymbolImplemented {
- ERC20Bytes32 asset = new ERC20Bytes32();
- string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(asset));
+ function test_GivenSymbolAsBytes32() external whenTokenContract givenSymbolImplemented {
+ ERC20Bytes32 token = new ERC20Bytes32();
+ string memory actualSymbol = nftDescriptorMock.safeTokenSymbol_(address(token));
string memory expectedSymbol = "ERC20";
assertEq(actualSymbol, expectedSymbol, "symbol");
}
function test_GivenSymbolLongerThan30Chars()
external
- whenAssetContract
+ whenTokenContract
givenSymbolImplemented
givenSymbolAsString
{
- ERC20Mock asset = new ERC20Mock({
+ ERC20Mock token = new ERC20Mock({
name: "Token",
symbol: "This symbol is has more than 30 characters and it should be ignored"
});
- string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(asset));
+ string memory actualSymbol = nftDescriptorMock.safeTokenSymbol_(address(token));
string memory expectedSymbol = "Long Symbol";
assertEq(actualSymbol, expectedSymbol, "symbol");
}
function test_GivenSymbolContainsNon_alphanumericChars()
external
- whenAssetContract
+ whenTokenContract
givenSymbolImplemented
givenSymbolAsString
givenSymbolNotLongerThan30Chars
{
- ERC20Mock asset = new ERC20Mock({ name: "Token", symbol: "