From efe4c50d71f3a69bf4447797b9d01fda888a26f2 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Tue, 26 Nov 2024 14:59:36 +0200 Subject: [PATCH 1/5] refactor: rename asset to token --- README.md | 2 +- SECURITY.md | 2 +- script/GenerateSVG.s.sol | 4 +- script/Init.s.sol | 14 ++-- src/LockupNFTDescriptor.sol | 69 +++++++++-------- src/SablierBatchLockup.sol | 66 ++++++++--------- src/SablierLockup.sol | 14 ++-- src/abstracts/SablierLockupBase.sol | 24 +++--- src/interfaces/ISablierBatchLockup.sol | 24 +++--- src/interfaces/ISablierLockup.sol | 6 +- src/interfaces/ISablierLockupBase.sol | 62 ++++++++-------- src/interfaces/ISablierLockupRecipient.sol | 10 +-- src/libraries/Errors.sol | 2 +- src/libraries/NFTSVG.sol | 14 ++-- src/libraries/VestingMath.sol | 4 +- src/types/DataTypes.sol | 74 +++++++++---------- tests/Base.t.sol | 24 +++--- tests/fork/Fork.t.sol | 32 ++++---- tests/fork/LockupDynamic.t.sol | 46 ++++++------ tests/fork/LockupLinear.t.sol | 46 ++++++------ tests/fork/LockupTranched.t.sol | 46 ++++++------ tests/fork/assets/DAI.t.sol | 12 +-- tests/fork/assets/EURS.t.sol | 12 +-- tests/fork/assets/SHIB.t.sol | 12 +-- tests/fork/assets/USDC.t.sol | 12 +-- tests/fork/assets/USDT.t.sol | 12 +-- .../createWithDurationsLD.t.sol | 2 +- .../createWithDurationsLL.t.sol | 2 +- .../createWithDurationsLT.t.sol | 2 +- .../createWithTimestampsLD.t.sol | 2 +- .../createWithTimestamps.t.sol | 2 +- .../createWithTimestampsLT.t.sol | 2 +- .../cancel-multiple/cancelMultiple.t.sol | 4 +- .../createWithTimestamps.t.sol | 4 +- .../createWithTimestamps.tree | 2 +- .../lockup-base/getters/getters.t.sol | 28 +++---- .../concrete/lockup-base/getters/getters.tree | 4 +- .../lockup-base/status-of/statusOf.t.sol | 10 +-- .../lockup-base/status-of/statusOf.tree | 4 +- .../withdrawMaxAndTransfer.t.sol | 10 +-- .../withdrawMaxAndTransfer.tree | 2 +- .../withdraw-max/withdrawMax.t.sol | 8 +- .../withdraw-multiple/withdrawMultiple.t.sol | 6 +- .../lockup-base/withdraw/withdraw.t.sol | 8 +- .../createWithDurationsLD.t.sol | 2 +- .../createWithTimestampsLD.t.sol | 32 ++++---- .../createWithTimestampsLD.tree | 6 +- .../lockup-dynamic/token-uri/tokenURI.t.sol | 4 +- .../createWithDurationsLL.t.sol | 2 +- .../createWithTimestampsLL.t.sol | 36 ++++----- .../createWithTimestampsLL.tree | 6 +- .../lockup-linear/token-uri/tokenURI.t.sol | 4 +- .../createWithDurationsLT.t.sol | 2 +- .../createWithTimestampsLT.t.sol | 34 ++++----- .../createWithTimestampsLT.tree | 6 +- .../lockup-tranched/token-uri/tokenURI.t.sol | 4 +- .../safeAssetDecimals.t.sol | 14 ++-- .../safeAssetDecimals.tree | 6 +- .../safe-asset-symbol/safeAssetSymbol.t.sol | 32 ++++---- .../safe-asset-symbol/safeAssetSymbol.tree | 6 +- .../integration/fuzz/lockup-base/cancel.t.sol | 2 +- .../fuzz/lockup-base/withdraw.t.sol | 4 +- .../fuzz/lockup-base/withdrawMax.t.sol | 8 +- .../lockup-base/withdrawMaxAndTransfer.t.sol | 4 +- .../createWithDurationsLD.t.sol | 6 +- .../createWithTimestampsLD.t.sol | 16 ++-- .../lockup-dynamic/streamedAmountOf.t.sol | 6 +- .../fuzz/lockup-dynamic/withdraw.t.sol | 6 +- .../lockup-linear/createWithDurationsLL.t.sol | 4 +- .../createWithTimestampsLL.t.sol | 16 ++-- .../fuzz/lockup-linear/streamedAmountOf.t.sol | 6 +- .../lockup-linear/withdrawableAmountOf.t.sol | 4 +- .../createWithDurationsLT.t.sol | 6 +- .../createWithTimestampsLT.t.sol | 16 ++-- .../lockup-tranched/streamedAmountOf.t.sol | 4 +- .../fuzz/lockup-tranched/withdraw.t.sol | 6 +- tests/invariant/Invariant.t.sol | 4 +- tests/invariant/handlers/BaseHandler.sol | 8 +- .../handlers/LockupCreateHandler.sol | 62 ++++++++-------- tests/invariant/handlers/LockupHandler.sol | 2 +- tests/mocks/NFTDescriptorMock.sol | 18 ++--- .../nft-descriptor/generateAttributes.t.sol | 4 +- .../nft-descriptor/generateDescription.t.sol | 6 +- .../concrete/nft-descriptor/generateSVG.t.sol | 12 +-- tests/utils/Defaults.sol | 22 +++--- tests/utils/Modifiers.sol | 8 +- 86 files changed, 607 insertions(+), 596 deletions(-) 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..98e50a45b 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); + // Load the token's address based on the contract version. + if (vars.lockupModel.equal("Sablier Lockup")) { + // If the Lockup contract is the latest version, use the `getToken` function. + vars.token = address(vars.lockup.getToken(streamId)); + } + // Otherwise, if there is an older version of the Lockup contract, use the `getAsset` function. + else { + (, bytes memory returnData) = + address(lockup).staticcall(abi.encodeWithSelector(bytes4(keccak256("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 { '', SVGElements.BACKGROUND, generateDefs(params.accentColor, params.status, vars.cards), - generateFloatingText(params.lockupAddress, params.lockupModel, params.assetAddress, params.assetSymbol), + generateFloatingText(params.lockupAddress, params.lockupModel, params.tokenAddress, params.tokenSymbol), generateHrefs(vars.progressXPosition, vars.statusXPosition, vars.amountXPosition, vars.durationXPosition), "" ); @@ -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/assets/DAI.t.sol index e96fd5b5b..075f223a1 100644 --- a/tests/fork/assets/DAI.t.sol +++ b/tests/fork/assets/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/assets/EURS.t.sol index ea6dc8520..2502c8416 100644 --- a/tests/fork/assets/EURS.t.sol +++ b/tests/fork/assets/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/assets/SHIB.t.sol index 0f10927f1..3f6ea23d7 100644 --- a/tests/fork/assets/SHIB.t.sol +++ b/tests/fork/assets/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/assets/USDC.t.sol index dce918831..c166e0dc4 100644 --- a/tests/fork/assets/USDC.t.sol +++ b/tests/fork/assets/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/assets/USDT.t.sol index 6bee0e6b1..4bae90eb8 100644 --- a/tests/fork/assets/USDT.t.sol +++ b/tests/fork/assets/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..30094c5e2 100644 --- a/tests/integration/concrete/lockup-base/getters/getters.tree +++ b/tests/integration/concrete/lockup-base/getters/getters.tree @@ -1,8 +1,8 @@ -Getters_Integration_Concrete_Test::getAsset +Getters_Integration_Concrete_Test::getToken ├── given null │ └── it should revert └── given not null - └── it should return the correct address of the asset + └── it should return the correct address of the token Getters_Integration_Concrete_Test::getDepositedAmount ├── given null 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-asset-decimals/safeAssetDecimals.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-asset-decimals/safeAssetDecimals.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-asset-decimals/safeAssetDecimals.tree index b1515423b..6cd270a57 100644 --- a/tests/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.tree +++ b/tests/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.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-asset-symbol/safeAssetSymbol.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-asset-symbol/safeAssetSymbol.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: "" }); - string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(asset)); + ERC20Mock token = new ERC20Mock({ name: "Token", symbol: "" }); + string memory actualSymbol = nftDescriptorMock.safeTokenSymbol_(address(token)); string memory expectedSymbol = "Unsupported Symbol"; assertEq(actualSymbol, expectedSymbol, "symbol"); } @@ -57,12 +57,12 @@ contract SafeAssetSymbol_Integration_Concrete_Test is Base_Test { function test_GivenSymbolContainsAlphanumericChars() external view - whenAssetContract + whenTokenContract givenSymbolImplemented givenSymbolAsString givenSymbolNotLongerThan30Chars { - string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(dai)); + string memory actualSymbol = nftDescriptorMock.safeTokenSymbol_(address(dai)); string memory expectedSymbol = dai.symbol(); assertEq(actualSymbol, expectedSymbol, "symbol"); } diff --git a/tests/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree b/tests/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree index 7fb1e9bf5..055d93378 100644 --- a/tests/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree +++ b/tests/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree @@ -1,7 +1,7 @@ -SafeAssetSymbol_Integration_Concrete_Test -├── when asset not contract +SafeTokenSymbol_Integration_Concrete_Test +├── when token not contract │ └── it should return a hard-coded value -└── when asset contract +└── when token contract ├── given symbol not implemented │ └── it should return a hard-coded value └── given symbol implemented diff --git a/tests/integration/fuzz/lockup-base/cancel.t.sol b/tests/integration/fuzz/lockup-base/cancel.t.sol index 30b8f32f5..6ae8585e5 100644 --- a/tests/integration/fuzz/lockup-base/cancel.t.sol +++ b/tests/integration/fuzz/lockup-base/cancel.t.sol @@ -75,7 +75,7 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test { lockup.withdraw({ streamId: recipientGoodStreamId, to: address(recipientGood), amount: withdrawAmount }); } - // Expect the assets to be refunded to the Sender. + // Expect the tokens to be refunded to the Sender. uint128 senderAmount = lockup.refundableAmountOf(recipientGoodStreamId); expectCallToTransfer({ to: users.sender, value: senderAmount }); diff --git a/tests/integration/fuzz/lockup-base/withdraw.t.sol b/tests/integration/fuzz/lockup-base/withdraw.t.sol index 137b4e908..6e56752ce 100644 --- a/tests/integration/fuzz/lockup-base/withdraw.t.sol +++ b/tests/integration/fuzz/lockup-base/withdraw.t.sol @@ -109,7 +109,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test { uint128 withdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); withdrawAmount = boundUint128(withdrawAmount, 1, withdrawableAmount); - // Expect the assets to be transferred to the fuzzed `to` address. + // Expect the tokens to be transferred to the fuzzed `to` address. expectCallToTransfer({ to: to, value: withdrawAmount }); // Expect the relevant events to be emitted. @@ -172,7 +172,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test { uint128 withdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); withdrawAmount = boundUint128(withdrawAmount, 1, withdrawableAmount); - // Expect the assets to be transferred to the fuzzed `to` address. + // Expect the tokens to be transferred to the fuzzed `to` address. expectCallToTransfer({ to: to, value: withdrawAmount }); // Expect the relevant events to be emitted. diff --git a/tests/integration/fuzz/lockup-base/withdrawMax.t.sol b/tests/integration/fuzz/lockup-base/withdrawMax.t.sol index 79f3df863..03c36885f 100644 --- a/tests/integration/fuzz/lockup-base/withdrawMax.t.sol +++ b/tests/integration/fuzz/lockup-base/withdrawMax.t.sol @@ -13,7 +13,7 @@ contract WithdrawMax_Integration_Fuzz_Test is Integration_Test { // Simulate the passage of time. vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); - // 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() }); // Expect the relevant event to be emitted. @@ -21,7 +21,7 @@ contract WithdrawMax_Integration_Fuzz_Test is Integration_Test { emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, - asset: dai, + token: dai, amount: defaults.DEPOSIT_AMOUNT() }); @@ -57,7 +57,7 @@ contract WithdrawMax_Integration_Fuzz_Test is Integration_Test { // Get the withdraw amount. uint128 withdrawAmount = 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: withdrawAmount }); // Expect the relevant event to be emitted. @@ -65,7 +65,7 @@ contract WithdrawMax_Integration_Fuzz_Test is Integration_Test { emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, - asset: dai, + token: dai, amount: withdrawAmount }); diff --git a/tests/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol b/tests/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol index 7d171e202..b5bf2adcd 100644 --- a/tests/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol +++ b/tests/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol @@ -33,7 +33,7 @@ contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is Integration_Test { uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); if (withdrawAmount > 0) { - // Expect the assets to be transferred to the fuzzed recipient. + // Expect the tokens to be transferred to the fuzzed recipient. expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); // Expect the relevant event to be emitted. @@ -41,7 +41,7 @@ contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is Integration_Test { emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, - asset: dai, + token: dai, amount: withdrawAmount }); } diff --git a/tests/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol b/tests/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol index 7016c0c31..3ee92c02f 100644 --- a/tests/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol +++ b/tests/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol @@ -41,10 +41,10 @@ contract CreateWithDurationsLD_Integration_Fuzz_Test is Lockup_Dynamic_Integrati uint256 expectedStreamId = lockup.nextStreamId(); - // Mint enough assets to the fuzzed funder. + // Mint enough tokens to the fuzzed funder. deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); - // Expect the assets to be transferred from the funder to {SablierLockup}. + // Expect the tokens to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: vars.funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. @@ -79,7 +79,7 @@ contract CreateWithDurationsLD_Integration_Fuzz_Test is Lockup_Dynamic_Integrati // It should create the stream. assertEq(lockup.getDepositedAmount(streamId), vars.createAmounts.deposit, "depositedAmount"); - assertEq(lockup.getAsset(streamId), dai, "asset"); + assertEq(lockup.getToken(streamId), dai, "token"); assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), vars.isCancelable, "isCancelable"); assertFalse(lockup.isDepleted(streamId), "isDepleted"); diff --git a/tests/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol b/tests/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol index 3872f41e1..13474b9d6 100644 --- a/tests/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol +++ b/tests/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol @@ -190,8 +190,8 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Dynamic_Integrat whenTimestampsStrictlyIncreasing whenDepositAmountNotEqualSegmentAmountsSum whenBrokerFeeNotExceedMaxValue - whenAssetContract - whenAssetERC20 + whenTokenContract + whenTokenERC20 { vm.assume( funder != address(0) && params.sender != address(0) && params.recipient != address(0) @@ -200,7 +200,7 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Dynamic_Integrat vm.assume(segments.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.asset = dai; + params.token = dai; params.timestamps.start = boundUint40(params.timestamps.start, 1, defaults.START_TIME()); params.transferable = true; @@ -223,13 +223,13 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Dynamic_Integrat uint256 expectedStreamId = lockup.nextStreamId(); - // Mint enough assets to the fuzzed funder. + // Mint enough tokens to the fuzzed funder. deal({ token: address(dai), to: funder, give: vars.totalAmount }); - // Approve {SablierLockup} to transfer the assets from the fuzzed funder. + // Approve {SablierLockup} to transfer the tokens from the fuzzed funder. dai.approve({ spender: address(lockup), value: MAX_UINT256 }); - // Expect the assets to be transferred from the funder to {SablierLockup}. + // Expect the tokens to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. @@ -246,7 +246,7 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Dynamic_Integrat sender: params.sender, recipient: params.recipient, amounts: vars.createAmounts, - asset: dai, + token: dai, cancelable: params.cancelable, transferable: params.transferable, timestamps: params.timestamps, @@ -266,7 +266,7 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Dynamic_Integrat // It should create the stream. assertEq(lockup.getDepositedAmount(streamId), vars.createAmounts.deposit, "depositedAmount"); - assertEq(lockup.getAsset(streamId), dai, "asset"); + assertEq(lockup.getToken(streamId), dai, "token"); assertEq(lockup.getEndTime(streamId), params.timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), vars.isCancelable, "isCancelable"); assertFalse(lockup.isDepleted(streamId), "isDepleted"); diff --git a/tests/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol b/tests/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index d19981cad..08bc533dd 100644 --- a/tests/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/tests/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -31,7 +31,7 @@ contract StreamedAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Lockup_Dynamic LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](1); segments[0] = segment; - // Mint enough assets to the Sender. + // Mint enough tokens to the Sender. deal({ token: address(dai), to: users.sender, give: segment.amount }); // Create the stream with the fuzzed segment. @@ -83,7 +83,7 @@ contract StreamedAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Lockup_Dynamic uint40 totalDuration = segments[segments.length - 1].timestamp - defaults.START_TIME(); timeJump = boundUint40(timeJump, firstSegmentDuration, totalDuration + 100 seconds); - // Mint enough assets to the Sender. + // Mint enough tokens to the Sender. deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed segments. @@ -130,7 +130,7 @@ contract StreamedAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Lockup_Dynamic timeWarp0 = boundUint40(timeWarp0, firstSegmentDuration, totalDuration - 1); timeWarp1 = boundUint40(timeWarp1, timeWarp0, totalDuration); - // Mint enough assets to the Sender. + // Mint enough tokens to the Sender. deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed segments. diff --git a/tests/integration/fuzz/lockup-dynamic/withdraw.t.sol b/tests/integration/fuzz/lockup-dynamic/withdraw.t.sol index 9b7249d5d..ff04b5c68 100644 --- a/tests/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/tests/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -67,7 +67,7 @@ contract Withdraw_Lockup_Dynamic_Integration_Fuzz_Test is vars.totalDuration = params.segments[params.segments.length - 1].timestamp - defaults.START_TIME(); params.timeJump = _bound(params.timeJump, 1 seconds, vars.totalDuration + 100 seconds); - // Mint enough assets to the funder. + // Mint enough tokens to the funder. deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); // Make the Sender the caller. @@ -94,7 +94,7 @@ contract Withdraw_Lockup_Dynamic_Integration_Fuzz_Test is // Bound the withdraw amount. vars.withdrawAmount = boundUint128(vars.withdrawAmount, 1, vars.withdrawableAmount); - // Expect the assets to be transferred to the fuzzed `to` address. + // Expect the tokens to be transferred to the fuzzed `to` address. expectCallToTransfer({ to: params.to, value: vars.withdrawAmount }); // Expect the relevant events to be emitted. @@ -103,7 +103,7 @@ contract Withdraw_Lockup_Dynamic_Integration_Fuzz_Test is streamId: vars.streamId, to: params.to, amount: vars.withdrawAmount, - asset: dai + token: dai }); vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); diff --git a/tests/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol b/tests/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol index 9df5450b3..b9972b7ba 100644 --- a/tests/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol +++ b/tests/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol @@ -48,7 +48,7 @@ contract CreateWithDurationsLL_Integration_Fuzz_Test is Lockup_Linear_Integratio address funder = users.sender; uint256 expectedStreamId = lockup.nextStreamId(); - // Expect the assets to be transferred from the funder to {SablierLockup}. + // Expect the tokens to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: funder, to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. @@ -77,7 +77,7 @@ contract CreateWithDurationsLL_Integration_Fuzz_Test is Lockup_Linear_Integratio // It should create the stream. 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/fuzz/lockup-linear/createWithTimestampsLL.t.sol b/tests/integration/fuzz/lockup-linear/createWithTimestampsLL.t.sol index 600b61f26..be53fa94d 100644 --- a/tests/integration/fuzz/lockup-linear/createWithTimestampsLL.t.sol +++ b/tests/integration/fuzz/lockup-linear/createWithTimestampsLL.t.sol @@ -128,8 +128,8 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Linear_Integrati whenStartTimeNotZero whenCliffTimeLessThanEndTime whenBrokerFeeNotExceedMaxValue - whenAssetContract - whenAssetERC20 + whenTokenContract + whenTokenERC20 { vm.assume( funder != address(0) && params.sender != address(0) && params.recipient != address(0) @@ -167,13 +167,13 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Linear_Integrati resetPrank(funder); vars.expectedStreamId = lockup.nextStreamId(); - // Mint enough assets to the funder. + // Mint enough tokens to the funder. deal({ token: address(dai), to: funder, give: params.totalAmount }); - // Approve {SablierLockup} to transfer the assets from the fuzzed funder. + // Approve {SablierLockup} to transfer the tokens from the fuzzed funder. dai.approve({ spender: address(lockup), value: MAX_UINT256 }); - // Expect the assets to be transferred from the funder to {SablierLockup}. + // Expect the tokens to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. @@ -190,7 +190,7 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Linear_Integrati sender: params.sender, recipient: params.recipient, amounts: vars.createAmounts, - asset: dai, + token: dai, cancelable: params.cancelable, transferable: params.transferable, timestamps: Lockup.Timestamps({ start: params.timestamps.start, end: params.timestamps.end }), @@ -201,14 +201,14 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Linear_Integrati unlockAmounts: unlockAmounts }); - params.asset = dai; + params.token = dai; // Create the stream. vars.actualStreamId = lockup.createWithTimestampsLL(params, unlockAmounts, cliffTime); // It should create the stream. assertEq(lockup.getDepositedAmount(vars.actualStreamId), vars.createAmounts.deposit, "depositedAmount"); - assertEq(lockup.getAsset(vars.actualStreamId), dai, "asset"); + assertEq(lockup.getToken(vars.actualStreamId), dai, "token"); assertEq(lockup.getEndTime(vars.actualStreamId), params.timestamps.end, "endTime"); assertEq(lockup.isCancelable(vars.actualStreamId), params.cancelable, "isCancelable"); assertFalse(lockup.isDepleted(vars.actualStreamId), "isDepleted"); diff --git a/tests/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/tests/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index 86e39ad46..ecbfe9498 100644 --- a/tests/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/tests/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -22,7 +22,7 @@ contract StreamedAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Linear_I unlockAmounts.start = boundUint128(unlockAmounts.start, 0, depositAmount); unlockAmounts.cliff = boundUint128(unlockAmounts.start, 0, depositAmount - unlockAmounts.start); - // Mint enough assets to the Sender. + // Mint enough tokens to the Sender. deal({ token: address(dai), to: users.sender, give: depositAmount }); // Approve the lockup contract to transfer the deposit amount. @@ -65,7 +65,7 @@ contract StreamedAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Linear_I unlockAmounts.start = boundUint128(unlockAmounts.start, 0, depositAmount); unlockAmounts.cliff = boundUint128(unlockAmounts.start, 0, depositAmount - unlockAmounts.start); - // Mint enough assets to the Sender. + // Mint enough tokens to the Sender. deal({ token: address(dai), to: users.sender, give: depositAmount }); // Approve the lockup contract to transfer the deposit amount. @@ -108,7 +108,7 @@ contract StreamedAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Linear_I unlockAmounts.start = boundUint128(unlockAmounts.start, 0, depositAmount); unlockAmounts.cliff = boundUint128(unlockAmounts.start, 0, depositAmount - unlockAmounts.start); - // Mint enough assets to the Sender. + // Mint enough tokens to the Sender. deal({ token: address(dai), to: users.sender, give: depositAmount }); // Approve the lockup contract to transfer the deposit amount. diff --git a/tests/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/tests/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index 9d63eb772..45d33051f 100644 --- a/tests/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/tests/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -37,7 +37,7 @@ contract WithdrawableAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Line vm.assume(depositAmount != 0); timeJump = boundUint40(timeJump, defaults.WARP_26_PERCENT_DURATION(), defaults.TOTAL_DURATION() * 2); - // Mint enough assets to the Sender. + // Mint enough tokens to the Sender. deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream. The broker fee is disabled so that it doesn't interfere with the calculations. @@ -85,7 +85,7 @@ contract WithdrawableAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Line { depositAmount = boundUint128(depositAmount, 10_000, MAX_UINT128); - // Mint enough assets to the Sender. + // Mint enough tokens to the Sender. deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream. The broker fee is disabled so that it doesn't interfere with the calculations. diff --git a/tests/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol b/tests/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol index 9f1e057ff..6022bc390 100644 --- a/tests/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol +++ b/tests/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol @@ -41,10 +41,10 @@ contract CreateWithDurationsLT_Integration_Fuzz_Test is Lockup_Tranched_Integrat vars.funder = users.sender; uint256 expectedStreamId = lockup.nextStreamId(); - // Mint enough assets to the fuzzed funder. + // Mint enough tokens to the fuzzed funder. deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); - // Expect the assets to be transferred from the funder to {SablierLockup}. + // Expect the tokens to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: vars.funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. @@ -79,7 +79,7 @@ contract CreateWithDurationsLT_Integration_Fuzz_Test is Lockup_Tranched_Integrat // It should create the stream. assertEq(lockup.getDepositedAmount(streamId), vars.createAmounts.deposit, "depositedAmount"); - assertEq(lockup.getAsset(streamId), dai, "asset"); + assertEq(lockup.getToken(streamId), dai, "token"); assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), vars.isCancelable, "isCancelable"); assertFalse(lockup.isDepleted(streamId), "isDepleted"); diff --git a/tests/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol b/tests/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol index 097df2356..653d982e9 100644 --- a/tests/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol +++ b/tests/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol @@ -196,8 +196,8 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Tranched_Integra whenTrancheTimestampsAreOrdered whenDepositAmountNotEqualTrancheAmountsSum whenBrokerFeeNotExceedMaxValue - whenAssetContract - whenAssetERC20 + whenTokenContract + whenTokenERC20 { vm.assume( funder != address(0) && params.sender != address(0) && params.recipient != address(0) @@ -206,7 +206,7 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Tranched_Integra vm.assume(tranches.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.asset = dai; + params.token = dai; params.timestamps.start = boundUint40(params.timestamps.start, 1, defaults.START_TIME()); params.transferable = true; @@ -227,13 +227,13 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Tranched_Integra // Make the fuzzed funder the caller in the rest of this test. resetPrank(funder); - // Mint enough assets to the fuzzed funder. + // Mint enough tokens to the fuzzed funder. deal({ token: address(dai), to: funder, give: vars.totalAmount }); - // Approve {SablierLockup} to transfer the assets from the fuzzed funder. + // Approve {SablierLockup} to transfer the tokens from the fuzzed funder. dai.approve({ spender: address(lockup), value: MAX_UINT256 }); - // Expect the assets to be transferred from the funder to {SablierLockup}. + // Expect the tokens to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. @@ -252,7 +252,7 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Tranched_Integra sender: params.sender, recipient: params.recipient, amounts: vars.createAmounts, - asset: dai, + token: dai, cancelable: params.cancelable, transferable: params.transferable, timestamps: params.timestamps, @@ -272,7 +272,7 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Tranched_Integra // It should create the stream. assertEq(lockup.getDepositedAmount(streamId), vars.createAmounts.deposit, "depositedAmount"); - assertEq(lockup.getAsset(streamId), dai, "asset"); + assertEq(lockup.getToken(streamId), dai, "token"); assertEq(lockup.getEndTime(streamId), params.timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), vars.isCancelable, "isCancelable"); assertFalse(lockup.isDepleted(streamId), "isDepleted"); diff --git a/tests/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol b/tests/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol index 040ebef57..c2834adad 100644 --- a/tests/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol +++ b/tests/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol @@ -40,7 +40,7 @@ contract StreamedAmountOf_Lockup_Tranched_Integration_Fuzz_Test is Lockup_Tranch uint40 totalDuration = tranches[tranches.length - 1].timestamp - defaults.START_TIME(); timeJump = boundUint40(timeJump, firstTrancheDuration, totalDuration + 100 seconds); - // Mint enough assets to the Sender. + // Mint enough tokens to the Sender. deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed tranches. @@ -87,7 +87,7 @@ contract StreamedAmountOf_Lockup_Tranched_Integration_Fuzz_Test is Lockup_Tranch timeWarp0 = boundUint40(timeWarp0, firstTrancheDuration, totalDuration - 1); timeWarp1 = boundUint40(timeWarp1, timeWarp0, totalDuration); - // Mint enough assets to the Sender. + // Mint enough tokens to the Sender. deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed tranches. diff --git a/tests/integration/fuzz/lockup-tranched/withdraw.t.sol b/tests/integration/fuzz/lockup-tranched/withdraw.t.sol index 80b056993..ebd64c010 100644 --- a/tests/integration/fuzz/lockup-tranched/withdraw.t.sol +++ b/tests/integration/fuzz/lockup-tranched/withdraw.t.sol @@ -66,7 +66,7 @@ contract Withdraw_Lockup_Tranched_Integration_Fuzz_Test is vars.totalDuration = params.tranches[params.tranches.length - 1].timestamp - defaults.START_TIME(); params.timeJump = _bound(params.timeJump, 1 seconds, vars.totalDuration + 100 seconds); - // Mint enough assets to the funder. + // Mint enough tokens to the funder. deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); // Make the Sender the caller. @@ -96,7 +96,7 @@ contract Withdraw_Lockup_Tranched_Integration_Fuzz_Test is // Make the Recipient the caller. resetPrank({ msgSender: users.recipient }); - // Expect the assets to be transferred to the fuzzed `to` address. + // Expect the tokens to be transferred to the fuzzed `to` address. expectCallToTransfer({ to: params.to, value: vars.withdrawAmount }); // Expect the relevant events to be emitted. @@ -104,7 +104,7 @@ contract Withdraw_Lockup_Tranched_Integration_Fuzz_Test is emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: vars.streamId, to: params.to, - asset: dai, + token: dai, amount: vars.withdrawAmount }); vm.expectEmit({ emitter: address(lockup) }); diff --git a/tests/invariant/Invariant.t.sol b/tests/invariant/Invariant.t.sol index 3954c1e45..fa06cdb6b 100644 --- a/tests/invariant/Invariant.t.sol +++ b/tests/invariant/Invariant.t.sol @@ -30,8 +30,8 @@ contract Invariant_Test is Base_Test, StdInvariant { vm.label({ account: address(lockupStore), newLabel: "LockupStore" }); // Deploy the Lockup handlers. - createHandler = new LockupCreateHandler({ asset_: dai, lockupStore_: lockupStore, lockup_: lockup }); - handler = new LockupHandler({ asset_: dai, lockupStore_: lockupStore, lockup_: lockup }); + createHandler = new LockupCreateHandler({ token_: dai, lockupStore_: lockupStore, lockup_: lockup }); + handler = new LockupHandler({ token_: dai, lockupStore_: lockupStore, lockup_: lockup }); // Label the contracts. vm.label({ account: address(createHandler), newLabel: "LockupCreateHandler" }); diff --git a/tests/invariant/handlers/BaseHandler.sol b/tests/invariant/handlers/BaseHandler.sol index 91729834a..bf267b3c1 100644 --- a/tests/invariant/handlers/BaseHandler.sol +++ b/tests/invariant/handlers/BaseHandler.sol @@ -29,15 +29,15 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Default ERC-20 asset used for testing. - IERC20 public asset; + /// @dev Default ERC-20 token used for testing. + IERC20 public token; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(IERC20 asset_, ISablierLockup lockup_) { - asset = asset_; + constructor(IERC20 token_, ISablierLockup lockup_) { + token = token_; lockup = lockup_; } diff --git a/tests/invariant/handlers/LockupCreateHandler.sol b/tests/invariant/handlers/LockupCreateHandler.sol index 3d68e3176..1eb84fdb8 100644 --- a/tests/invariant/handlers/LockupCreateHandler.sol +++ b/tests/invariant/handlers/LockupCreateHandler.sol @@ -22,7 +22,7 @@ contract LockupCreateHandler is BaseHandler, Calculations { CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockup lockup_) BaseHandler(asset_, lockup_) { + constructor(IERC20 token_, LockupStore lockupStore_, ISablierLockup lockup_) BaseHandler(token_, lockup_) { lockupStore = lockupStore_; } @@ -57,14 +57,14 @@ contract LockupCreateHandler is BaseHandler, Calculations { (params.totalAmount,) = fuzzDynamicStreamAmounts({ upperBound: 1_000_000_000e18, segments: segments, brokerFee: params.broker.fee }); - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + // Mint enough tokens to the Sender. + deal({ token: address(token), to: params.sender, give: token.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierLockup} to spend the assets. - asset.approve({ spender: address(lockup), value: params.totalAmount }); + // Approve {SablierLockup} to spend the tokens. + token.approve({ spender: address(lockup), value: params.totalAmount }); // Create the stream. - params.asset = asset; + params.token = token; params.shape = "Dynamic Stream"; uint256 streamId = lockup.createWithDurationsLD(params, segments); @@ -89,14 +89,14 @@ contract LockupCreateHandler is BaseHandler, Calculations { (params, unlockAmounts, durations) = _boundCreateWithDurationsLLParams(params, unlockAmounts, durations); - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + // Mint enough tokens to the Sender. + deal({ token: address(token), to: params.sender, give: token.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierLockup} to spend the assets. - asset.approve({ spender: address(lockup), value: params.totalAmount }); + // Approve {SablierLockup} to spend the tokens. + token.approve({ spender: address(lockup), value: params.totalAmount }); // Create the stream. - params.asset = asset; + params.token = token; params.shape = "Linear Stream"; uint256 streamId = lockup.createWithDurationsLL(params, unlockAmounts, durations); @@ -134,14 +134,14 @@ contract LockupCreateHandler is BaseHandler, Calculations { brokerFee: params.broker.fee }); - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + // Mint enough tokens to the Sender. + deal({ token: address(token), to: params.sender, give: token.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierLockup} to spend the assets. - asset.approve({ spender: address(lockup), value: params.totalAmount }); + // Approve {SablierLockup} to spend the tokens. + token.approve({ spender: address(lockup), value: params.totalAmount }); // Create the stream. - params.asset = asset; + params.token = token; params.shape = "Tranched Stream"; uint256 streamId = lockup.createWithDurationsLT(params, tranches); @@ -176,14 +176,14 @@ contract LockupCreateHandler is BaseHandler, Calculations { (params.totalAmount,) = fuzzDynamicStreamAmounts({ upperBound: 1_000_000_000e18, segments: segments, brokerFee: params.broker.fee }); - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + // Mint enough tokens to the Sender. + deal({ token: address(token), to: params.sender, give: token.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierLockup} to spend the assets. - asset.approve({ spender: address(lockup), value: params.totalAmount }); + // Approve {SablierLockup} to spend the tokens. + token.approve({ spender: address(lockup), value: params.totalAmount }); // Create the stream. - params.asset = asset; + params.token = token; params.shape = "Dynamic Stream"; params.timestamps.end = segments[segments.length - 1].timestamp; uint256 streamId = lockup.createWithTimestampsLD(params, segments); @@ -209,14 +209,14 @@ contract LockupCreateHandler is BaseHandler, Calculations { (params, unlockAmounts, cliffTime) = _boundCreateWithTimestampsLLParams(params, unlockAmounts, cliffTime); - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + // Mint enough tokens to the Sender. + deal({ token: address(token), to: params.sender, give: token.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierLockup} to spend the assets. - asset.approve({ spender: address(lockup), value: params.totalAmount }); + // Approve {SablierLockup} to spend the tokens. + token.approve({ spender: address(lockup), value: params.totalAmount }); // Create the stream. - params.asset = asset; + params.token = token; params.shape = "Linear Stream"; uint256 streamId = lockup.createWithTimestampsLL(params, unlockAmounts, cliffTime); @@ -254,14 +254,14 @@ contract LockupCreateHandler is BaseHandler, Calculations { brokerFee: params.broker.fee }); - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + // Mint enough tokens to the Sender. + deal({ token: address(token), to: params.sender, give: token.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierLockup} to spend the assets. - asset.approve({ spender: address(lockup), value: params.totalAmount }); + // Approve {SablierLockup} to spend the tokens. + token.approve({ spender: address(lockup), value: params.totalAmount }); // Create the stream. - params.asset = asset; + params.token = token; params.shape = "Tranched Stream"; params.timestamps.end = tranches[tranches.length - 1].timestamp; uint256 streamId = lockup.createWithTimestampsLT(params, tranches); diff --git a/tests/invariant/handlers/LockupHandler.sol b/tests/invariant/handlers/LockupHandler.sol index f556d102f..20c6bb2fe 100644 --- a/tests/invariant/handlers/LockupHandler.sol +++ b/tests/invariant/handlers/LockupHandler.sol @@ -28,7 +28,7 @@ contract LockupHandler is BaseHandler { CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockup lockup_) BaseHandler(asset_, lockup_) { + constructor(IERC20 token_, LockupStore lockupStore_, ISablierLockup lockup_) BaseHandler(token_, lockup_) { lockupStore = lockupStore_; } diff --git a/tests/mocks/NFTDescriptorMock.sol b/tests/mocks/NFTDescriptorMock.sol index dd0d47cf0..811a07b5f 100644 --- a/tests/mocks/NFTDescriptorMock.sol +++ b/tests/mocks/NFTDescriptorMock.sol @@ -39,7 +39,7 @@ contract NFTDescriptorMock is LockupNFTDescriptor { } function generateAttributes_( - string memory assetSymbol, + string memory tokenSymbol, string memory sender, string memory status ) @@ -47,14 +47,14 @@ contract NFTDescriptorMock is LockupNFTDescriptor { pure returns (string memory) { - return generateAttributes(assetSymbol, sender, status); + return generateAttributes(tokenSymbol, sender, status); } function generateDescription_( string memory lockupModel, - string memory assetSymbol, + string memory tokenSymbol, string memory lockupAddress, - string memory assetAddress, + string memory tokenAddress, string memory streamId, bool isTransferable ) @@ -62,7 +62,7 @@ contract NFTDescriptorMock is LockupNFTDescriptor { pure returns (string memory) { - return generateDescription(lockupModel, assetSymbol, lockupAddress, assetAddress, streamId, isTransferable); + return generateDescription(lockupModel, tokenSymbol, lockupAddress, tokenAddress, streamId, isTransferable); } function generateName_(string memory lockupModel, string memory streamId) external pure returns (string memory) { @@ -85,12 +85,12 @@ contract NFTDescriptorMock is LockupNFTDescriptor { return mapSymbol(nft); } - function safeAssetDecimals_(address asset) external view returns (uint8) { - return safeAssetDecimals(asset); + function safeTokenDecimals_(address token) external view returns (uint8) { + return safeTokenDecimals(token); } - function safeAssetSymbol_(address asset) external view returns (string memory) { - return safeAssetSymbol(asset); + function safeTokenSymbol_(address token) external view returns (string memory) { + return safeTokenSymbol(token); } function stringifyCardType_(SVGElements.CardType cardType) external pure returns (string memory) { diff --git a/tests/unit/concrete/nft-descriptor/generateAttributes.t.sol b/tests/unit/concrete/nft-descriptor/generateAttributes.t.sol index a190b2155..ff57916fd 100644 --- a/tests/unit/concrete/nft-descriptor/generateAttributes.t.sol +++ b/tests/unit/concrete/nft-descriptor/generateAttributes.t.sol @@ -8,7 +8,7 @@ contract GenerateAttributes_Unit_Concrete_Test is Base_Test { function test_GenerateAttributes_Empty() external view { string memory actualAttributes = nftDescriptorMock.generateAttributes_("", "", ""); string memory expectedAttributes = - '[{"trait_type":"Asset","value":""},{"trait_type":"Sender","value":""},{"trait_type":"Status","value":""}]'; + '[{"trait_type":"Token","value":""},{"trait_type":"Sender","value":""},{"trait_type":"Status","value":""}]'; assertEq(actualAttributes, expectedAttributes, "metadata attributes"); } @@ -16,7 +16,7 @@ contract GenerateAttributes_Unit_Concrete_Test is Base_Test { string memory actualAttributes = nftDescriptorMock.generateAttributes_("DAI", "0x50725493D337CdC4e381f658e10d29d128BD6927", "Streaming"); string memory expectedAttributes = - '[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x50725493D337CdC4e381f658e10d29d128BD6927"},{"trait_type":"Status","value":"Streaming"}]'; + '[{"trait_type":"Token","value":"DAI"},{"trait_type":"Sender","value":"0x50725493D337CdC4e381f658e10d29d128BD6927"},{"trait_type":"Status","value":"Streaming"}]'; assertEq(actualAttributes, expectedAttributes, "metadata attributes"); } } diff --git a/tests/unit/concrete/nft-descriptor/generateDescription.t.sol b/tests/unit/concrete/nft-descriptor/generateDescription.t.sol index 683f58e8e..972b33d6f 100644 --- a/tests/unit/concrete/nft-descriptor/generateDescription.t.sol +++ b/tests/unit/concrete/nft-descriptor/generateDescription.t.sol @@ -14,7 +14,7 @@ contract GenerateDescription_Unit_Concrete_Test is Base_Test { string memory actualDescription = nftDescriptorMock.generateDescription_("", "", "", "", "", true); string memory expectedDescription = string.concat( "This NFT represents a payment stream in a Sablier Lockup ", - " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ", + " contract. The owner of this NFT can withdraw the streamed tokens, which are denominated in ", ".\\n\\n", "- Stream ID: ", "\\n- ", @@ -39,7 +39,7 @@ contract GenerateDescription_Unit_Concrete_Test is Base_Test { string memory expectedDescription = string.concat( "This NFT represents a payment stream in a Sablier Lockup ", "Lockup Linear", - " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ", + " contract. The owner of this NFT can withdraw the streamed tokens, which are denominated in ", dai.symbol(), ".\\n\\n", "- Stream ID: ", @@ -70,7 +70,7 @@ contract GenerateDescription_Unit_Concrete_Test is Base_Test { string memory expectedDescription = string.concat( "This NFT represents a payment stream in a Sablier Lockup ", "Lockup Linear", - " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ", + " contract. The owner of this NFT can withdraw the streamed tokens, which are denominated in ", dai.symbol(), ".\\n\\n", "- Stream ID: ", diff --git a/tests/unit/concrete/nft-descriptor/generateSVG.t.sol b/tests/unit/concrete/nft-descriptor/generateSVG.t.sol index 68187cfee..aa43e874c 100644 --- a/tests/unit/concrete/nft-descriptor/generateSVG.t.sol +++ b/tests/unit/concrete/nft-descriptor/generateSVG.t.sol @@ -16,8 +16,8 @@ contract GenerateSVG_Unit_Concrete_Test is Base_Test { NFTSVG.SVGParams({ accentColor: "hsl(155,18%,30%)", amount: "100", - assetAddress: "0x03a6a84cd762d9707a21605b548aaab891562aab", - assetSymbol: "DAI", + tokenAddress: "0x03a6a84cd762d9707a21605b548aaab891562aab", + tokenSymbol: "DAI", duration: "5 Days", progress: "0%", progressNumerical: 0, @@ -36,8 +36,8 @@ contract GenerateSVG_Unit_Concrete_Test is Base_Test { NFTSVG.SVGParams({ accentColor: "hsl(114,3%,53%)", amount: string.concat(SVGElements.SIGN_GE, " 1.23M"), - assetAddress: "0x03a6a84cd762d9707a21605b548aaab891562aab", - assetSymbol: "DAI", + tokenAddress: "0x03a6a84cd762d9707a21605b548aaab891562aab", + tokenSymbol: "DAI", duration: "91 Days", progress: "42.35%", progressNumerical: 4235, @@ -56,8 +56,8 @@ contract GenerateSVG_Unit_Concrete_Test is Base_Test { NFTSVG.SVGParams({ accentColor: "hsl(123,25%,44%)", amount: "100", - assetAddress: "0x03a6a84cd762d9707a21605b548aaab891562aab", - assetSymbol: "DAI", + tokenAddress: "0x03a6a84cd762d9707a21605b548aaab891562aab", + tokenSymbol: "DAI", duration: "5 Days", progress: "100%", progressNumerical: 100, diff --git a/tests/utils/Defaults.sol b/tests/utils/Defaults.sol index 0b7bda601..4b0f1aa43 100644 --- a/tests/utils/Defaults.sol +++ b/tests/utils/Defaults.sol @@ -47,7 +47,7 @@ contract Defaults is Constants { VARIABLES //////////////////////////////////////////////////////////////////////////*/ - IERC20 private asset; + IERC20 private token; Users private users; /*////////////////////////////////////////////////////////////////////////// @@ -66,8 +66,8 @@ contract Defaults is Constants { HELPERS //////////////////////////////////////////////////////////////////////////*/ - function setAsset(IERC20 asset_) public { - asset = asset_; + function setToken(IERC20 token_) public { + token = token_; } function setUsers(Users memory users_) public { @@ -98,8 +98,8 @@ contract Defaults is Constants { return Lockup.CreateAmounts({ deposit: DEPOSIT_AMOUNT, brokerFee: BROKER_FEE_AMOUNT }); } - function lockupCreateEvent(IERC20 asset_) public view returns (Lockup.CreateEventCommon memory) { - return lockupCreateEvent(asset_, lockupCreateAmounts(), lockupTimestamps()); + function lockupCreateEvent(IERC20 token_) public view returns (Lockup.CreateEventCommon memory) { + return lockupCreateEvent(token_, lockupCreateAmounts(), lockupTimestamps()); } function lockupCreateEvent(Lockup.Timestamps memory timestamps) @@ -107,7 +107,7 @@ contract Defaults is Constants { view returns (Lockup.CreateEventCommon memory) { - return lockupCreateEvent(asset, lockupCreateAmounts(), timestamps); + return lockupCreateEvent(token, lockupCreateAmounts(), timestamps); } function lockupCreateEvent( @@ -118,11 +118,11 @@ contract Defaults is Constants { view returns (Lockup.CreateEventCommon memory) { - return lockupCreateEvent(asset, createAmounts, timestamps); + return lockupCreateEvent(token, createAmounts, timestamps); } function lockupCreateEvent( - IERC20 asset_, + IERC20 token_, Lockup.CreateAmounts memory createAmounts, Lockup.Timestamps memory timestamps ) @@ -135,7 +135,7 @@ contract Defaults is Constants { sender: users.sender, recipient: users.recipient, amounts: createAmounts, - asset: asset_, + token: token_, cancelable: true, transferable: true, timestamps: timestamps, @@ -218,7 +218,7 @@ contract Defaults is Constants { sender: users.sender, recipient: users.recipient, totalAmount: TOTAL_AMOUNT, - asset: asset, + token: token, cancelable: true, transferable: true, broker: broker(), @@ -237,7 +237,7 @@ contract Defaults is Constants { sender: users.sender, recipient: users.recipient, totalAmount: TOTAL_AMOUNT, - asset: asset, + token: token, cancelable: true, transferable: true, timestamps: lockupTimestamps(), diff --git a/tests/utils/Modifiers.sol b/tests/utils/Modifiers.sol index f05768581..0200e8204 100644 --- a/tests/utils/Modifiers.sol +++ b/tests/utils/Modifiers.sol @@ -77,11 +77,11 @@ abstract contract Modifiers is Fuzzers { _; } - modifier whenAssetContract() { + modifier whenTokenContract() { _; } - modifier whenAssetERC20() { + modifier whenTokenERC20() { _; } @@ -324,7 +324,7 @@ abstract contract Modifiers is Fuzzers { } /*////////////////////////////////////////////////////////////////////////// - SAFE-ASSET-SYMBOL + SAFE-TOKEN-SYMBOL //////////////////////////////////////////////////////////////////////////*/ modifier givenSymbolImplemented() { @@ -355,7 +355,7 @@ abstract contract Modifiers is Fuzzers { STATUS-OF //////////////////////////////////////////////////////////////////////////*/ - modifier givenAssetsNotFullyWithdrawn() { + modifier givenTokensNotFullyWithdrawn() { _; } From 8ee043b2094be3fa974a383f001df0512f788454 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Tue, 26 Nov 2024 17:23:58 +0200 Subject: [PATCH 2/5] chore: improve wording in explanatory comments --- src/LockupNFTDescriptor.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LockupNFTDescriptor.sol b/src/LockupNFTDescriptor.sol index 98e50a45b..83ccf5eb0 100644 --- a/src/LockupNFTDescriptor.sol +++ b/src/LockupNFTDescriptor.sol @@ -72,10 +72,10 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor { // Load the token's address based on the contract version. if (vars.lockupModel.equal("Sablier Lockup")) { - // If the Lockup contract is the latest version, use the `getToken` function. + // For the latest version of the Lockup contract, use the `getToken` function. vars.token = address(vars.lockup.getToken(streamId)); } - // Otherwise, if there is an older version of the Lockup contract, use the `getAsset` function. + // For older versions of the Lockup contract, use the `getAsset` function. else { (, bytes memory returnData) = address(lockup).staticcall(abi.encodeWithSelector(bytes4(keccak256("getAsset(uint256)")), streamId)); From 4190f38999ae90ced0b8a9c7d914fc268d2e9fe7 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Tue, 26 Nov 2024 18:16:41 +0200 Subject: [PATCH 3/5] test: move below getToken in getters tree --- .../concrete/lockup-base/getters/getters.tree | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/integration/concrete/lockup-base/getters/getters.tree b/tests/integration/concrete/lockup-base/getters/getters.tree index 30094c5e2..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::getToken -├── given null -│ └── it should revert -└── given not null - └── it should return the correct address of the token - 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 From 2a1ea6d82b84b018153d5b54b783f53fe9861cd1 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 26 Nov 2024 16:16:50 +0000 Subject: [PATCH 4/5] chore: reordering --- tests/utils/Modifiers.sol | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/utils/Modifiers.sol b/tests/utils/Modifiers.sol index 0200e8204..6071a26f3 100644 --- a/tests/utils/Modifiers.sol +++ b/tests/utils/Modifiers.sol @@ -77,14 +77,6 @@ abstract contract Modifiers is Fuzzers { _; } - modifier whenTokenContract() { - _; - } - - modifier whenTokenERC20() { - _; - } - modifier whenCallerAdmin() { // Make the Admin the caller in the rest of this test suite. resetPrank({ msgSender: users.admin }); @@ -121,6 +113,14 @@ abstract contract Modifiers is Fuzzers { _; } + modifier whenTokenContract() { + _; + } + + modifier whenTokenERC20() { + _; + } + /*////////////////////////////////////////////////////////////////////////// BATCH //////////////////////////////////////////////////////////////////////////*/ From 0ce7109772c0a7b625ed36ec1014f12128ecdaef Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Tue, 26 Nov 2024 18:30:09 +0200 Subject: [PATCH 5/5] shub feedback Co-authored-by: smol-ninja --- src/LockupNFTDescriptor.sol | 8 ++++---- tests/fork/{assets => tokens}/DAI.t.sol | 0 tests/fork/{assets => tokens}/EURS.t.sol | 0 tests/fork/{assets => tokens}/SHIB.t.sol | 0 tests/fork/{assets => tokens}/USDC.t.sol | 0 tests/fork/{assets => tokens}/USDT.t.sol | 0 .../safeTokenDecimals.t.sol} | 0 .../safeTokenDecimals.tree} | 0 .../safeTokenSymbol.t.sol} | 0 .../safeTokenSymbol.tree} | 0 10 files changed, 4 insertions(+), 4 deletions(-) rename tests/fork/{assets => tokens}/DAI.t.sol (100%) rename tests/fork/{assets => tokens}/EURS.t.sol (100%) rename tests/fork/{assets => tokens}/SHIB.t.sol (100%) rename tests/fork/{assets => tokens}/USDC.t.sol (100%) rename tests/fork/{assets => tokens}/USDT.t.sol (100%) rename tests/integration/concrete/nft-descriptor/{safe-asset-decimals/safeAssetDecimals.t.sol => safe-token-decimals/safeTokenDecimals.t.sol} (100%) rename tests/integration/concrete/nft-descriptor/{safe-asset-decimals/safeAssetDecimals.tree => safe-token-decimals/safeTokenDecimals.tree} (100%) rename tests/integration/concrete/nft-descriptor/{safe-asset-symbol/safeAssetSymbol.t.sol => safe-token-symbol/safeTokenSymbol.t.sol} (100%) rename tests/integration/concrete/nft-descriptor/{safe-asset-symbol/safeAssetSymbol.tree => safe-token-symbol/safeTokenSymbol.tree} (100%) diff --git a/src/LockupNFTDescriptor.sol b/src/LockupNFTDescriptor.sol index 83ccf5eb0..3f52571c2 100644 --- a/src/LockupNFTDescriptor.sol +++ b/src/LockupNFTDescriptor.sol @@ -70,15 +70,15 @@ contract LockupNFTDescriptor is ILockupNFTDescriptor { vars.tokenSymbol = safeTokenSymbol(vars.token); vars.depositedAmount = vars.lockup.getDepositedAmount(streamId); - // Load the token's address based on the contract version. + // Retrieve the token's address based on the Lockup contract version. if (vars.lockupModel.equal("Sablier Lockup")) { - // For the latest version of the Lockup contract, use the `getToken` function. + // For Lockup contract versions v2.0.0 and later, use the `getToken` function. vars.token = address(vars.lockup.getToken(streamId)); } - // For older versions of the Lockup contract, use the `getAsset` function. + // For Lockup contract versions earlier than v2.0.0, use the `getAsset` function. else { (, bytes memory returnData) = - address(lockup).staticcall(abi.encodeWithSelector(bytes4(keccak256("getAsset(uint256)")), streamId)); + address(lockup).staticcall(abi.encodeWithSignature("getAsset(uint256)", streamId)); vars.token = abi.decode(returnData, (address)); } diff --git a/tests/fork/assets/DAI.t.sol b/tests/fork/tokens/DAI.t.sol similarity index 100% rename from tests/fork/assets/DAI.t.sol rename to tests/fork/tokens/DAI.t.sol diff --git a/tests/fork/assets/EURS.t.sol b/tests/fork/tokens/EURS.t.sol similarity index 100% rename from tests/fork/assets/EURS.t.sol rename to tests/fork/tokens/EURS.t.sol diff --git a/tests/fork/assets/SHIB.t.sol b/tests/fork/tokens/SHIB.t.sol similarity index 100% rename from tests/fork/assets/SHIB.t.sol rename to tests/fork/tokens/SHIB.t.sol diff --git a/tests/fork/assets/USDC.t.sol b/tests/fork/tokens/USDC.t.sol similarity index 100% rename from tests/fork/assets/USDC.t.sol rename to tests/fork/tokens/USDC.t.sol diff --git a/tests/fork/assets/USDT.t.sol b/tests/fork/tokens/USDT.t.sol similarity index 100% rename from tests/fork/assets/USDT.t.sol rename to tests/fork/tokens/USDT.t.sol 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 100% 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 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 100% rename from tests/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.tree rename to tests/integration/concrete/nft-descriptor/safe-token-decimals/safeTokenDecimals.tree 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 100% 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 diff --git a/tests/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree b/tests/integration/concrete/nft-descriptor/safe-token-symbol/safeTokenSymbol.tree similarity index 100% rename from tests/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree rename to tests/integration/concrete/nft-descriptor/safe-token-symbol/safeTokenSymbol.tree