Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"settings": {
"viaIR": true,
"evmVersion": "cancun",
"optimizer": {
"enabled": true,
"runs": 100
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"@openzeppelin-upgradeable/contracts/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"forge-gas-snapshot/=lib/forge-gas-snapshot/",
"forge-std-1.10.0/=dependencies/forge-std-1.10.0/",
"forge-std/=lib/forge-std/",
"permit2/=lib/permit2/",
"solmate/=lib/solmate/",
"@openzeppelin-upgradeable/contracts/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"forge-gas-snapshot/=lib/forge-gas-snapshot/",
"forge-std-1.10.0/=dependencies/forge-std-1.10.0/",
"forge-std/=lib/forge-std/",
"permit2/=lib/permit2/",
"solmate/=lib/solmate/",
"@openzeppelin-upgradeable/contracts/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"forge-gas-snapshot/=lib/forge-gas-snapshot/",
"forge-std-1.10.0/=dependencies/forge-std-1.10.0/",
"forge-std/=lib/forge-std/",
"permit2/=lib/permit2/",
"solmate/=lib/solmate/"
]
},
"sources": {
"src/TTSwap_Market.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;
import {I_TTSwap_Market, S_ProofState, S_GoodState, S_ProofKey, S_GoodTmpState} from "./interfaces/I_TTSwap_Market.sol";
import {L_Good} from "./libraries/L_Good.sol";
import {L_Transient} from "./libraries/L_Transient.sol";
import {TTSwapError} from "./libraries/L_Error.sol";
import {L_Proof, L_ProofIdLibrary} from "./libraries/L_Proof.sol";
import {L_GoodConfigLibrary} from "./libraries/L_GoodConfig.sol";
import {L_UserConfigLibrary} from "./libraries/L_UserConfig.sol";
import {L_CurrencyLibrary} from "./libraries/L_Currency.sol";
import {L_TTSwapUINT256Library, toTTSwapUINT256, add, lowerprice} from "./libraries/L_TTSwapUINT256.sol";
import {IMulticall_v4} from "./interfaces/IMulticall_v4.sol";
import {I_TTSwap_Token} from "./interfaces/I_TTSwap_Token.sol";
/**
* @title TTSwap_Market
* @author ttswap.exchange@gmail.com
* @dev Core market contract for TTSwap protocol that manages goods trading, investing, and staking operations
* @notice This contract implements a decentralized market system with the following key features:
* - Meta good, value goods, and normal goods management
* - Automated market making (AMM) with configurable fees
* - Investment and disinvestment mechanisms
* - Commission distribution system
* website http://www.ttswap.io
* twitter https://x.com/ttswapfinance
* telegram https://t.me/ttswapfinance
* discord https://discord.gg/XygqnmQgX3
*/
contract TTSwap_Market is I_TTSwap_Market, IMulticall_v4 {
using L_GoodConfigLibrary for uint256;
using L_UserConfigLibrary for uint256;
using L_ProofIdLibrary for S_ProofKey;
using L_TTSwapUINT256Library for uint256;
using L_Good for S_GoodState;
using L_Proof for S_ProofState;
using L_CurrencyLibrary for address;
/**
* @dev Address of the official TTS token contract
* @notice Handles:
* - Minting rewards for market participation
* - Staking operations and rewards
* - Referral tracking and rewards
* - Governance token functionality
*/
I_TTSwap_Token private immutable TTS_CONTRACT;
/// @notice Address of the security keeper
/// @dev The address of the security keeper
/// @custom:security The address of the security keeper when deploy market contract
/// @custom:security The address of the security keeper will be removed by market admin when contract run safety
address internal securitykeeper;
/**
* @dev Mapping of good addresses to their state information
* @notice Stores the complete state of each good including:
* - Current trading state(invest quantity & current quantity)
* - Investment state (invest shares & invest value)
* - Owner information
* - Configuration parameters
*/
mapping(address goodid => S_GoodState) private goods;
/**
* @dev Mapping of proof IDs to their state information
* @notice Records all investment proofs in the system:
* shares amount0:normal good shares amount1:value good shares
* state amount0:total value : amount1:total actual value
* invest amount0:normal good virtual quantity amount1:normal good actual quantity
* valueinvest amount0:value good virtual quantity amount1:value good actual quantity
*/
mapping(uint256 proofid => S_ProofState) private proofs;
/**
* @dev Constructor for TTSwap_Market
* @param _TTS_Contract The address of the official token contract
* @param _securitykeeper The address of the security keeper
*/
constructor(I_TTSwap_Token _TTS_Contract, address _securitykeeper) {
TTS_CONTRACT = _TTS_Contract;
securitykeeper = _securitykeeper;
}
/// only market admin can execute
modifier onlyMarketadmin() {
if (!TTS_CONTRACT.userConfig(msg.sender).isMarketAdmin())
revert TTSwapError(1);
_;
}
/// only market manager can execute
modifier onlyMarketor() {
if (!TTS_CONTRACT.userConfig(msg.sender).isMarketManager())
revert TTSwapError(2);
_;
}
/// run when eth token transfer to market contract
modifier msgValue() {
L_Transient.checkbefore();
_;
L_Transient.checkafter();
}
/// @notice This will revert if the contract is locked
modifier noReentrant() {
if (L_Transient.get() != address(0)) revert TTSwapError(3);
L_Transient.set(msg.sender);
_;
L_Transient.set(address(0));
}
/// @notice Enables calling multiple methods in a single call to the contract
/// @inheritdoc IMulticall_v4
function multicall(
bytes[] calldata data
) external payable msgValue returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
(bool success, bytes memory result) = address(this).delegatecall(
data[i]
);
if (!success) {
// bubble up the revert reason
assembly {
revert(add(result, 0x20), mload(result))
}
}
results[i] = result;
}
}
/**
* @dev Initializes a meta good with initial liquidity
* @param _erc20address The address of the ERC20 token to be used as the meta good
* @param _initial The initial liquidity amounts:
* - amount0: Initial token value
* - amount1: Initial token amount
* @param _goodConfig Configuration parameters for the good:
* - Fee rates (trading, investment)
* - Trading limits (min/max amounts)
* - Special flags ( emergency pause)
* @param data Additional data for token transfer
* @return bool Success status of the initialization
* @notice This function:
* - Creates a new meta good with specified parameters
* - Sets up initial liquidity pool
* - Mints corresponding tokens to the market creator
* - Initializes proof tracking
* - Emits initialization events
* @custom:security Only callable by market admin
*/
/// @inheritdoc I_TTSwap_Market
function initMetaGood(
address _erc20address,
uint256 _initial,
uint256 _goodConfig,
bytes calldata data
) external payable onlyMarketadmin msgValue returns (bool) {
if (!_goodConfig.isvaluegood()) revert TTSwapError(4);
if (goods[_erc20address].owner != address(0)) revert TTSwapError(5);
_erc20address.transferFrom(msg.sender, _initial.amount1(), data);
goods[_erc20address].init(_initial, _goodConfig);
/// update good to value good & initialize good config
goods[_erc20address].modifyGoodConfig(0x30d4204000000000000000000000000000000000000000000000000000000000); //6*2**28+ 1*2**24+ 5*2**21+8*2**16+8*2**11+2*2**6
goods[_erc20address].modifyGoodCoreConfig(0x8000000000000000000000000000000000000000000000000000000000000000);//2**255
uint256 proofid = S_ProofKey(msg.sender, _erc20address, address(0))
.toId();
proofs[proofid].updateInvest(
_erc20address,
address(0),
toTTSwapUINT256(_initial.amount1(), 0),
toTTSwapUINT256(_initial.amount0(), _initial.amount0()),
toTTSwapUINT256(_initial.amount1(), _initial.amount1()),
0
);
uint128 construct = L_Proof.stake(
TTS_CONTRACT,
msg.sender,
_initial.amount0()
);
emit e_initMetaGood(
proofid,
_erc20address,
construct,
_goodConfig,
_initial
);
return true;
}
/**
* @dev Initializes a good
* @param _valuegood The value good ID
* @param _initial The initial balance,amount0 is the amount of the normal good,amount1 is the amount of the value good
* @param _erc20address The address of the ERC20 token
* @param _goodConfig The good configuration
* @param _normaldata The data of the normal good
* @param _valuedata The data of the value good
* @return bool Returns true if successful
*/
/// @inheritdoc I_TTSwap_Market
function initGood(
address _valuegood,
uint256 _initial,
address _erc20address,
uint256 _goodConfig,
bytes calldata _normaldata,
bytes calldata _valuedata
) external payable override noReentrant msgValue returns (bool) {
if (_initial.amount0() < 500000 || _initial.amount0() > 2 ** 109)
revert TTSwapError(36);
if (!goods[_valuegood].goodConfig.isvaluegood()) {
revert TTSwapError(6);
}
if (goods[_erc20address].owner != address(0)) revert TTSwapError(5);
_erc20address.transferFrom(msg.sender, _initial.amount0(), _normaldata);
_valuegood.transferFrom(msg.sender, _initial.amount1(), _valuedata);
L_Good.S_GoodInvestReturn memory investResult;
(investResult.goodShares, investResult.goodValues) = goods[_valuegood]
.investState
.amount01();
(
investResult.goodInvestQuantity,
investResult.goodCurrentQuantity
) = goods[_valuegood].currentState.amount01();
goods[_valuegood].investGood(_initial.amount1(), investResult, 1);
if (investResult.investValue < 500000000) revert TTSwapError(35);
goods[_erc20address].init(
toTTSwapUINT256(investResult.investValue, _initial.amount0()),
_goodConfig
);
uint256 proofId = S_ProofKey(msg.sender, _erc20address, _valuegood)
.toId();
proofs[proofId] = S_ProofState(
_erc20address,
_valuegood,
toTTSwapUINT256(_initial.amount0(), investResult.investShare),
toTTSwapUINT256(investResult.investValue, investResult.investValue),
toTTSwapUINT256(_initial.amount0(), _initial.amount0()),
toTTSwapUINT256(
investResult.investQuantity,
investResult.investQuantity
)
);
emit e_initGood(
proofId,
_erc20address,
_valuegood,
_goodConfig,
L_Proof.stake(
TTS_CONTRACT,
msg.sender,
investResult.investValue * 2
),
toTTSwapUINT256(_initial.amount0(), investResult.investValue), // amount0: the quantity of the normal good,amount1: the value of the value good
toTTSwapUINT256(
investResult.investFeeQuantity, // amount0: the fee of the value good
investResult.investQuantity // amount1: the quantity of the value good
)
);
return true;
}
/**
* @dev Executes a buy order between two goods
* @param _goodid1 The address of the input good
* @param _goodid2 The address of the output good
* @param _swapQuantity The amount of _goodid1 to swap
* - amount0: The quantity of the input good
* - amount1: The limit quantity of the output good
* @param _side 0:for pay 1for buy
* @param _recipent The address to receive referral rewards
* @param data Additional data for token transfer
* @return good1change The amount of _goodid1 used:
* - amount0: Trading fees
* - amount1: Actual swap amount
* @return good2change The amount of _goodid2 received:
* - amount0: Trading fees
* - amount1: Actual received amount
* @notice This function:
* - Calculates optimal swap amounts using AMM formulas
* - Applies trading fees and updates fee states
* - Updates good states and reserves
* - Handles referral rewards and distributions
* - Emits trade events with detailed information
* @custom:security Protected by reentrancy guard
* @custom:security Validates input parameters and state
*/
/// @inheritdoc I_TTSwap_Market
function buyGood(
address _goodid1,
address _goodid2,
uint256 _swapQuantity,
uint128 _side,
address _recipent,
bytes calldata data
)
external
payable
noReentrant
msgValue
returns (uint256 good1change, uint256 good2change)
{
if (_side > 1) revert TTSwapError(8);
if (_goodid1 == _goodid2) revert TTSwapError(9);
if (goods[_goodid1].goodConfig.isFreeze()) revert TTSwapError(10);
if (goods[_goodid2].goodConfig.isFreeze()) revert TTSwapError(11);
if (goods[_goodid1].currentState == 0) revert TTSwapError(12);
if (goods[_goodid2].currentState == 0) revert TTSwapError(13);
if (_side == 1) {
if (_recipent != address(0) && _recipent != msg.sender) {
TTS_CONTRACT.setReferral(msg.sender, _recipent);
}
if (
goods[_goodid1].currentState.amount1() +
_swapQuantity.amount0() >
goods[_goodid1].currentState.amount1() *
2 -
goods[_goodid1].goodConfig.amount1()
) revert TTSwapError(33);
L_Good.swapCache memory swapcache = L_Good.swapCache({
remainQuantity: _swapQuantity.amount0(),
outputQuantity: 0,
feeQuantity: 0,
swapvalue: 0,
good1value: goods[_goodid1].investState.amount1(),
good2value: goods[_goodid2].investState.amount1(),
good1currentState: goods[_goodid1].currentState,
good1config: goods[_goodid1].goodConfig,
good2currentState: goods[_goodid2].currentState,
good2config: goods[_goodid2].goodConfig
});
L_Good.swapCompute1(swapcache);
if (swapcache.swapvalue < 1_000_000) revert TTSwapError(14);
if (
swapcache.outputQuantity < _swapQuantity.amount1() &&
_swapQuantity.amount1() > 0
) revert TTSwapError(15);
if (
swapcache.good2currentState.amount1() <
(swapcache.good2config.amount1() * 11) / 10
) revert TTSwapError(16);
if (
swapcache.good2currentState.amount1() <
swapcache.good2currentState.amount0() / 10
) revert TTSwapError(16);
swapcache.good1currentState = add(
swapcache.good1currentState,
toTTSwapUINT256(swapcache.feeQuantity, _swapQuantity.amount0())
);
good1change = toTTSwapUINT256(
swapcache.feeQuantity,
_swapQuantity.amount0() - swapcache.feeQuantity
);
// compute Token2 fee quantity
_side = swapcache.good2config.getBuyFee(swapcache.outputQuantity);
// add fee quantity to token2 pool
swapcache.good2currentState = add(
swapcache.good2currentState,
toTTSwapUINT256(_side, _side)
);
good2change = toTTSwapUINT256(_side, swapcache.outputQuantity);
goods[_goodid1].swapCommit(swapcache.good1currentState);
goods[_goodid2].swapCommit(swapcache.good2currentState);
_goodid1.transferFrom(msg.sender, _swapQuantity.amount0(), data);
_goodid2.safeTransfer(msg.sender, good2change.amount1() - _side);
emit e_buyGood(
_goodid1,
_goodid2,
swapcache.swapvalue,
good1change,
good2change
);
} else {
if (_recipent == address(0)) revert TTSwapError(32);
L_Good.swapCache memory swapcache = L_Good.swapCache({
remainQuantity: _swapQuantity.amount1(),
outputQuantity: 0,
feeQuantity: 0,
swapvalue: 0,
good1value: goods[_goodid1].investState.amount1(),
good2value: goods[_goodid2].investState.amount1(),
good1currentState: goods[_goodid1].currentState,
good1config: goods[_goodid1].goodConfig,
good2currentState: goods[_goodid2].currentState,
good2config: goods[_goodid2].goodConfig
});
L_Good.swapCompute2(swapcache);
_side = swapcache.good1config.getSellFee(swapcache.outputQuantity);
good1change = toTTSwapUINT256(_side, swapcache.outputQuantity);
if (swapcache.swapvalue < 1_000_000) revert TTSwapError(14);
if (
good1change.amount1() > _swapQuantity.amount0() &&
_swapQuantity.amount0() > 0
) revert TTSwapError(15);
if (
swapcache.good2currentState.amount1() <
(swapcache.good2config.amount1() * 11) / 10
) revert TTSwapError(16);
if (
swapcache.good2currentState.amount1() <
swapcache.good2currentState.amount0() / 10
) revert TTSwapError(16);
if (
goods[_goodid1].currentState.amount1() +
_swapQuantity.amount0() >
goods[_goodid1].currentState.amount0() *
2 -
goods[_goodid1].goodConfig.amount1()
) revert TTSwapError(33);
swapcache.good1currentState = add(
swapcache.good1currentState,
toTTSwapUINT256(_side, _side)
);
good2change = toTTSwapUINT256(
swapcache.feeQuantity,
_swapQuantity.amount1() - swapcache.feeQuantity
);
_goodid1.transferFrom(
msg.sender,
good1change.amount1() + _side,
data
);
goods[_goodid1].swapCommit(swapcache.good1currentState);
goods[_goodid2].swapCommit(swapcache.good2currentState);
_goodid2.safeTransfer(_recipent, _swapQuantity.amount1());
emit e_buyGood(
_goodid1,
_goodid2,
uint256(swapcache.swapvalue) * 2 ** 128,
good1change,
good2change
);
}
}
/**
* @dev Simulates a buy order between two goods to check expected amounts
* @param _goodid1 The address of the input good
* @param _goodid2 The address of the output good
* @param _swapQuantity The amount of _goodid1 to swap
* - amount0: The quantity of the input good
* - amount1: The limit quantity of the output good
* @param _side 1:for buy 0:for pay
* @return good1change The expected amount of _goodid1 to be used:
* - amount0: Expected trading fees
* - amount1: Expected swap amount
* @return good2change The expected amount of _goodid2 to be received:
* - amount0: Expected trading fees
* - amount1: Expected received amount
* @notice This function:
* - Simulates the buyGood operation without executing it
* - Uses the same AMM formulas as buyGood
* - Validates input parameters and market state
* - Returns expected amounts including fees
* - Useful for frontend price quotes and transaction previews
* @custom:security View function, does not modify state
* @custom:security Reverts if:
* - Either good is not initialized
* - Swap quantity is zero
* - Same good is used for both input and output
* - Trade times exceeds 200
* - Insufficient liquidity for the swap
*/
/// @inheritdoc I_TTSwap_Market
function buyGoodCheck(
address _goodid1,
address _goodid2,
uint256 _swapQuantity,
bool _side
) external view returns (uint256 good1change, uint256 good2change) {
if (_side) {
L_Good.swapCache memory swapcache = L_Good.swapCache({
remainQuantity: _swapQuantity.amount0(),
outputQuantity: 0,
feeQuantity: 0,
swapvalue: 0,
good1value: goods[_goodid1].investState.amount1(),
good2value: goods[_goodid2].investState.amount1(),
good1currentState: goods[_goodid1].currentState,
good1config: goods[_goodid1].goodConfig,
good2currentState: goods[_goodid2].currentState,
good2config: goods[_goodid2].goodConfig
});
L_Good.swapCompute1(swapcache);
good1change = toTTSwapUINT256(
swapcache.feeQuantity,
_swapQuantity.amount0() - swapcache.feeQuantity
);
good2change = toTTSwapUINT256(
swapcache.good2config.getBuyFee(swapcache.outputQuantity),
swapcache.outputQuantity
);
} else {
L_Good.swapCache memory swapcache = L_Good.swapCache({
remainQuantity: _swapQuantity.amount1(),
outputQuantity: 0,
feeQuantity: 0,
swapvalue: 0,
good1value: goods[_goodid1].investState.amount1(),
good2value: goods[_goodid2].investState.amount1(),
good1currentState: goods[_goodid1].currentState,
good1config: goods[_goodid1].goodConfig,
good2currentState: goods[_goodid2].currentState,
good2config: goods[_goodid2].goodConfig
});
L_Good.swapCompute2(swapcache);
good1change = toTTSwapUINT256(
goods[_goodid1].goodConfig.getSellFee(swapcache.outputQuantity),
swapcache.outputQuantity
);
good2change = toTTSwapUINT256(
swapcache.feeQuantity,
_swapQuantity.amount1() - swapcache.feeQuantity
);
}
}
/**
* @dev Invests in a good with optional value good backing
* @param _togood The address of the good to invest in
* @param _valuegood The address of the value good (can be address(0))
* @param _quantity The amount to invest _togood
* @param data1 Additional data for _togood transfer
* @param data2 Additional data for _valuegood transfer
* @return bool Success status of the investment
* @notice This function:
* - Processes investment in the target good
* - Optionally processes value good investment
* - Updates proof state
* - Mints corresponding tokens
* - Calculates and distributes fees
*/
/// @inheritdoc I_TTSwap_Market
function investGood(
address _togood,
address _valuegood,
uint128 _quantity,
bytes calldata data1,
bytes calldata data2
) external payable override noReentrant msgValue returns (bool) {
L_Good.S_GoodInvestReturn memory normalInvest_;
L_Good.S_GoodInvestReturn memory valueInvest_;
if (_togood == _valuegood) revert TTSwapError(9);
if (goods[_togood].goodConfig.isFreeze()) revert TTSwapError(10);
if (goods[_togood].currentState == 0) revert TTSwapError(12);
if (
!(goods[_togood].goodConfig.isvaluegood() ||
goods[_valuegood].goodConfig.isvaluegood())
) revert TTSwapError(17);
if (goods[_togood].currentState.amount1() + _quantity > 2 ** 109)
revert TTSwapError(18);
uint128 enpower = goods[_togood].goodConfig.getPower();
if (_valuegood != address(0)) {
enpower = enpower < goods[_valuegood].goodConfig.getPower()
? enpower
: goods[_valuegood].goodConfig.getPower();
}
_togood.transferFrom(msg.sender, _quantity, data1);
(normalInvest_.goodShares, normalInvest_.goodValues) = goods[_togood]
.investState
.amount01();
(
normalInvest_.goodInvestQuantity,
normalInvest_.goodCurrentQuantity
) = goods[_togood].currentState.amount01();
goods[_togood].investGood(_quantity, normalInvest_, enpower);
if (normalInvest_.investValue < 1000000) revert TTSwapError(38);
if (_valuegood != address(0)) {
if (goods[_valuegood].goodConfig.isFreeze()) revert TTSwapError(11);
if (goods[_valuegood].currentState == 0) revert TTSwapError(13);
(valueInvest_.goodShares, valueInvest_.goodValues) = goods[
_valuegood
].investState.amount01();
(
valueInvest_.goodInvestQuantity,
valueInvest_.goodCurrentQuantity
) = goods[_valuegood].currentState.amount01();
valueInvest_.investQuantity = toTTSwapUINT256(
valueInvest_.goodCurrentQuantity,
valueInvest_.goodValues
).getamount0fromamount1(normalInvest_.investValue);
valueInvest_.investQuantity = goods[_valuegood]
.goodConfig
.getInvestFullFee(valueInvest_.investQuantity);
goods[_valuegood].investGood(
valueInvest_.investQuantity,
valueInvest_,
enpower
);
_valuegood.transferFrom(
msg.sender,
valueInvest_.investQuantity /
enpower +
valueInvest_.investFeeQuantity,
data2
);
}
uint256 proofNo = S_ProofKey(msg.sender, _togood, _valuegood).toId();
uint128 investvalue = normalInvest_.investValue;
investvalue = (normalInvest_.investValue / enpower);
proofs[proofNo].updateInvest(
_togood,
_valuegood,
toTTSwapUINT256(
normalInvest_.investShare,
valueInvest_.investShare
),
toTTSwapUINT256(normalInvest_.investValue, investvalue),
toTTSwapUINT256(
normalInvest_.investQuantity,
normalInvest_.investQuantity / enpower //real quantity
),
toTTSwapUINT256(
valueInvest_.investQuantity,
valueInvest_.investQuantity / enpower
)
);
emit e_investGood(
proofNo,
_togood,
_valuegood,
toTTSwapUINT256(normalInvest_.investValue, investvalue),
toTTSwapUINT256(
normalInvest_.investFeeQuantity,
normalInvest_.investQuantity
),
toTTSwapUINT256(
valueInvest_.investFeeQuantity,
valueInvest_.investQuantity
)
);
investvalue = _valuegood == address(0) ? investvalue : investvalue * 2;
L_Proof.stake(TTS_CONTRACT, msg.sender, investvalue);
return true;
}
/**
* @dev Disinvests from a proof by withdrawing invested tokens and collecting profits
* @param _proofid The ID of the proof to disinvest from
* @param _goodQuantity The amount of normal good tokens to disinvest
* @param _gate The address to receive gate rewards (falls back to DAO admin if banned)
* @return uint128 The profit amount from normal good disinvestment
* @return uint128 The profit amount from value good disinvestment (if applicable)
* @notice This function:
* - Validates proof ownership and state
* - Processes disinvestment for both normal and value goods
* - Handles commission distribution and fee collection
* - Updates proof state and burns tokens
* - Distributes rewards to gate and referrer
* - Unstakes TTS tokens
* @custom:security Protected by noReentrant modifier
* @custom:security Reverts if:
* - Proof ID does not match sender's proof
* - Invalid proof state
* - Insufficient balance for disinvestment
*/
/// @inheritdoc I_TTSwap_Market
function disinvestProof(
uint256 _proofid,
uint128 _goodshares,
address _gate
) external override noReentrant returns (uint128, uint128) {
if (
S_ProofKey(
msg.sender,
proofs[_proofid].currentgood,
proofs[_proofid].valuegood
).toId() != _proofid
) {
revert TTSwapError(19);
}
L_Good.S_GoodDisinvestReturn memory disinvestNormalResult1_;
L_Good.S_GoodDisinvestReturn memory disinvestValueResult2_;
address normalgood = proofs[_proofid].currentgood;
if (goods[normalgood].goodConfig.isFreeze()) revert TTSwapError(10);
address valuegood = proofs[_proofid].valuegood;
uint256 divestvalue;
address referal = TTS_CONTRACT.getreferral(msg.sender);
_gate = TTS_CONTRACT.userConfig(_gate).isBan() ? address(0) : _gate;
referal = _gate == referal ? address(0) : referal;
referal = TTS_CONTRACT.userConfig(referal).isBan()
? address(0)
: referal;
(disinvestNormalResult1_, disinvestValueResult2_, divestvalue) = goods[
normalgood
].disinvestGood(
goods[valuegood],
proofs[_proofid],
L_Good.S_GoodDisinvestParam(_goodshares, _gate, referal)
);
uint256 tranferamount = goods[normalgood].commission[msg.sender];
if (tranferamount > 1) {
goods[normalgood].commission[msg.sender] = 1;
normalgood.safeTransfer(msg.sender, tranferamount - 1);
}
if (valuegood != address(0)) {
if (goods[valuegood].goodConfig.isFreeze()) revert TTSwapError(10);
tranferamount = goods[valuegood].commission[msg.sender];
if (tranferamount > 1) {
goods[valuegood].commission[msg.sender] = 1;
valuegood.safeTransfer(msg.sender, tranferamount - 1);
}
}
L_Proof.unstake(TTS_CONTRACT, msg.sender, divestvalue.amount0());
emit e_disinvestProof(
_proofid,
normalgood,
valuegood,
_gate,
divestvalue,
toTTSwapUINT256(
disinvestNormalResult1_.profit,
disinvestNormalResult1_.vitualDisinvestQuantity
),
toTTSwapUINT256(
disinvestNormalResult1_.actual_fee,
disinvestNormalResult1_.actualDisinvestQuantity
),
toTTSwapUINT256(
disinvestValueResult2_.profit,
disinvestValueResult2_.vitualDisinvestQuantity
),
toTTSwapUINT256(
disinvestValueResult2_.actual_fee,
disinvestValueResult2_.actualDisinvestQuantity
)
);
return (disinvestNormalResult1_.profit, disinvestValueResult2_.profit);
}
/**
* @dev Compares the current trading states of two goods to determine if the first good is in a higher iteration
* @param good1 The address of the first good to compare
* @param good2 The address of the second good to compare
* @param compareprice the price of use good2 for good1
* @return bool Returns true if good1's current state is higher than good2's, false otherwise
* @notice This function:
* - Compares the current trading iterations (states) of two goods
* - Used to determine the trading order and eligibility for operations
* - Essential for maintaining trading synchronization between goods
* - Returns false if either good is not registered (state = 0)
* @custom:security This is a view function with no state modifications
* @custom:security Returns false for unregistered goods to prevent invalid operations
*/
/// @inheritdoc I_TTSwap_Market
function ishigher(
address goodid,
address valuegood,
uint256 compareprice
) external view override returns (bool) {
return
lowerprice(
toTTSwapUINT256(
goods[goodid].investState.amount1(),
goods[goodid].currentState.amount1()
),
toTTSwapUINT256(
goods[valuegood].investState.amount1(),
goods[valuegood].currentState.amount1()
),
compareprice
);
}
/**
* @dev Retrieves the current state of two goods in a single call
* @param good1 The address of the first good to query
* @param good2 The address of the second good to query
* @return good1correntstate The current state of the first good, representing its latest trading iteration
* @return good2correntstate The current state of the second good, representing its latest trading iteration
* @notice This function is a view function that:
* - Returns the current trading iteration (state) for both goods
* - Useful for checking the latest trading status of a pair of goods
* - Can be used to verify if goods are in sync for trading operations
* @custom:security This is a view function with no state modifications
* @custom:security Returns 0 if either good address is not registered
*/
/// @inheritdoc I_TTSwap_Market
function getRecentGoodState(
address good1,
address good2
)
external
view
override
returns (uint256 good1currentstate, uint256 good2currentstate)
{
// return (goods[good1].currentState, goods[good2].currentState);
return (
toTTSwapUINT256(
goods[good1].investState.amount1(),
goods[good1].currentState.amount1()
),
toTTSwapUINT256(
goods[good2].investState.amount1(),
goods[good2].currentState.amount1()
)
);
}
/// @notice Retrieves the current state of a proof
/// @param proofid The ID of the proof to query
/// @return proofstate The current state of the proof,
/// currentgood The current good associated with the proof
/// valuegood The value good associated with the proof
/// shares normal good shares, value good shares
/// state Total value, Total actual value
/// invest normal good virtual quantity, normal good actual quantity
/// valueinvest value good virtual quantity, value good actual quantity
/// @inheritdoc I_TTSwap_Market
function getProofState(
uint256 proofid
) external view override returns (S_ProofState memory) {
return proofs[proofid];
}
/// @notice Retrieves the current state of a good
/// @param good The address of the good to query
/// @return goodstate The current state of the good,
/// goodConfig Configuration of the good, check goodconfig.sol or whitepaper for details
/// owner Creator of the good
/// currentState Present investQuantity, CurrentQuantity
/// investState Shares, value
/// @inheritdoc I_TTSwap_Market
function getGoodState(
address good
) external view override returns (S_GoodTmpState memory) {
return
S_GoodTmpState(
goods[good].goodConfig,
goods[good].owner,
goods[good].currentState,
goods[good].investState
);
}
/// @notice Updates a good's configuration
/// @param _goodid The ID of the good
/// @param _goodConfig The new configuration
/// @return Success status
/// @inheritdoc I_TTSwap_Market
function updateGoodConfig(
address _goodid,
uint256 _goodConfig
) external override returns (bool) {
if (msg.sender != goods[_goodid].owner) revert TTSwapError(20);
goods[_goodid].updateGoodConfig(_goodConfig);
emit e_updateGoodConfig(_goodid, goods[_goodid].goodConfig);
return true;
}
/// @param _goodid The ID of the good
/// @param _goodConfig The new configuration
/// @return Success status
/// @inheritdoc I_TTSwap_Market
function modifyGoodConfig(
address _goodid,
uint256 _goodConfig
) external override onlyMarketor returns (bool) {
if(!_goodConfig.checkGoodConfig()) revert TTSwapError(24);
goods[_goodid].modifyGoodConfig(_goodConfig);
emit e_modifyGoodConfig(_goodid, goods[_goodid].goodConfig);
return true;
}
/// @param _goodid The ID of the good
/// @param _goodConfig The new configuration
/// @return Success status
/// @inheritdoc I_TTSwap_Market
function modifyGoodCoreConfig(
address _goodid,
uint256 _goodConfig
) external override onlyMarketadmin returns (bool) {
goods[_goodid].modifyGoodCoreConfig(_goodConfig);
emit e_modifyGoodConfig(_goodid, goods[_goodid].goodConfig);
return true;
}
function lockGood(address _goodid) external override {
require(TTS_CONTRACT.userConfig(msg.sender).isMarketManager()||goods[_goodid].owner==msg.sender);
goods[_goodid].lockGood();
emit e_updateGoodConfig(_goodid, goods[_goodid].goodConfig);
}
/// @notice Changes the owner of a good
/// @param _goodid The ID of the good
/// @param _to The new owner's address
/// @inheritdoc I_TTSwap_Market
function changeGoodOwner(
address _goodid,
address _to
) external override onlyMarketor {
goods[_goodid].owner = _to;
emit e_changegoodowner(_goodid, _to);
}
/// @notice Collects commission for specified goods
/// @param _goodid Array of good IDs
/// @inheritdoc I_TTSwap_Market
function collectCommission(
address[] calldata _goodid
) external override noReentrant {
address recipent = TTS_CONTRACT.userConfig(msg.sender).isMarketAdmin()
? address(0)
: msg.sender;
if (_goodid.length > 100) revert TTSwapError(21);
uint256[] memory commissionamount = new uint256[](_goodid.length);
for (uint256 i = 0; i < _goodid.length; i++) {
commissionamount[i] = goods[_goodid[i]].commission[recipent];
if (commissionamount[i] > 2) {
commissionamount[i] = commissionamount[i] - 1;
goods[_goodid[i]].commission[recipent] = 1;
_goodid[i].safeTransfer(msg.sender, commissionamount[i]);
}
}
emit e_collectcommission(_goodid, commissionamount);
}
/**
* @dev Queries commission amounts for multiple goods for a specific recipient
* @param _goodid Array of good addresses to query commission for
* @param _recipent The address to check commission amounts for
* @return feeamount Array of commission amounts corresponding to each good
* @notice This function:
* - Returns commission amounts for up to 100 goods in a single call
* - Each amount represents the commission available for the recipient
* - Returns 0 for goods where no commission is available
* - Maintains gas efficiency by using a fixed array size
* @custom:security Reverts if more than 100 goods are queried
* @custom:security View function, does not modify state
*/
/// @inheritdoc I_TTSwap_Market
function queryCommission(
address[] calldata _goodid,
address _recipent
) external view override returns (uint256[] memory) {
if (_goodid.length > 100) revert TTSwapError(21);
uint256[] memory feeamount = new uint256[](_goodid.length);
for (uint256 i = 0; i < _goodid.length; i++) {
feeamount[i] = goods[_goodid[i]].commission[_recipent];
}
return feeamount;
}
/**
* @dev Adds welfare funds to a good's fee pool
* @param goodid The address of the good to receive welfare
* @param welfare The amount of tokens to add as welfare
* @param data Additional data for token transfer
* @notice This function:
* - Allows anyone to contribute additional funds to a good's fee pool
* - Increases the good's feeQuantityState by the welfare amount
* - Transfers tokens from the sender to the good
* - Emits an event with the welfare contribution details
* @custom:security Protected by noReentrant modifier
* @custom:security Checks for overflow in feeQuantityState
*/
/// @inheritdoc I_TTSwap_Market
function goodWelfare(
address goodid,
uint128 welfare,
bytes calldata data
) external payable override noReentrant msgValue {
if (goods[goodid].currentState.amount0() + welfare > 2 ** 109) {
revert TTSwapError(18);
}
goodid.transferFrom(msg.sender, welfare, data);
goods[goodid].currentState = add(
goods[goodid].currentState,
toTTSwapUINT256(uint128(welfare), uint128(welfare))
);
emit e_goodWelfare(goodid, welfare);
}
function removeSecurityKeeper() external onlyMarketadmin {
if (securitykeeper != msg.sender) revert TTSwapError(22);
securitykeeper = address(0);
}
function securityKeeper(address erc20) external noReentrant {
if (securitykeeper != msg.sender) revert TTSwapError(22);
if (!goods[erc20].goodConfig.isFreeze()) revert TTSwapError(34);
uint256 amount = erc20.balanceof(address(this));
erc20.safeTransfer(msg.sender, amount);
}
}
"
},
"src/interfaces/I_TTSwap_Token.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.29;
/// @title Investment Proof Interface
/// @notice Contains a series of interfaces for goods
interface I_TTSwap_Token {
/// @notice Emitted when environment variables are set
/// @param marketcontract The address of the market contract
event e_setenv(address marketcontract);
/// @notice Emitted when user config is updated
/// @param user The address of the user
/// @param config The new config value
event e_updateUserConfig(address user, uint256 config);
/// @notice Emitted when a referral relationship is added
/// @param user The address of the user being referred
event e_addreferral(address user, address referal);
/// @notice Emitted when minting is added
/// @param recipient The address receiving the minted tokens
/// @param leftamount The remaining amount to be minted
/// @param metric The metric used for minting
/// @param chips The number of chips
event e_addShare(
address recipient,
uint128 leftamount,
uint120 metric,
uint8 chips
);
/// @notice Emitted when minting is burned
/// @param owner The index of the minting operation being burned
event e_burnShare(address owner);
/// @notice Emitted when DAO minting occurs
/// @param mintamount The amount being minted
/// @param owner The index of the minting operation
event e_shareMint(uint128 mintamount, address owner);
/// @notice Emitted during a public sale
/// @param usdtamount The amount of USDT involved
/// @param ttsamount The amount of TTS involved
event e_publicsell(uint256 usdtamount, uint256 ttsamount);
/// @notice Emitted when chain stake is synchronized
/// @param chain The chain ID
/// @param poolasset The pool asset value
/// @param proofstate The value of the pool
//first 128 bit proofvalue,last 128 bit proofconstruct
event e_syncChainStake(uint32 chain, uint128 poolasset, uint256 proofstate);
/// @notice Emitted when unstaking occurs
/// @param recipient The address receiving the unstaked tokens
/// @param proofvalue first 128 bit proofvalue,last 128 bit poolcontruct
/// @param unstakestate The state after unstaking
/// @param stakestate The state of the stake
/// @param poolstate The state of the pool
event e_stakeinfo(
address recipient,
uint256 proofvalue,
uint256 unstakestate,
uint256 stakestate,
uint256 poolstate
);
/// @notice Emitted when the pool state is updated
/// @param poolstate The new state of the pool
event e_updatepool(uint256 poolstate);
/// @notice Emitted when the pool state is updated
/// @param ttsconfig The new state of the pool
event e_updatettsconfig(uint256 ttsconfig);
/**
* @dev Returns the share information for a given user address.
* @param user The address to query for share information.
* @return The s_share struct containing the user's share details.
*/
function usershares(address user) external view returns (s_share memory);
/**
* @dev Returns the current staking state.
* @return The staking state as a uint256 value.
*/
function stakestate() external view returns (uint256);
/**
* @dev Returns the current pool state.
* @return The pool state as a uint256 value.
*/
function poolstate() external view returns (uint256);
/**
* @dev Returns the TTS token configuration value.
* @return The configuration as a uint256 value.
*/
function ttstokenconfig() external view returns (uint256);
/**
* @dev Returns the amount of left share available for minting.
* @return The left share as a uint128 value.
*/
function left_share() external view returns (uint128);
/**
* @dev Returns the stake proof information for a given index.
* @param index The index to query for stake proof information.
* @return The s_proof struct containing the stake proof details.
*/
function stakeproofinfo(uint256 index) external view returns (s_proof memory);
/**
* @dev Sets the trading volume ratio for the protocol.
* @param _ratio The new ratio value (max 10000).
*/
function setRatio(uint256 _ratio) external;
/**
* @dev Grants or revokes DAO admin privileges to a recipient address.
* @param _recipient The address to grant or revoke DAO admin rights.
* @param result Boolean indicating whether to grant (true) or revoke (false) the privilege.
*/
function setDAOAdmin(address _recipient, bool result) external;
/**
* @dev Grants or revokes Token admin privileges to a recipient address.
* @param _recipient The address to grant or revoke Token admin rights.
* @param result Boolean indicating whether to grant (true) or revoke (false) the privilege.
*/
function setTokenAdmin(address _recipient, bool result) external;
/**
* @dev Grants or revokes Token manager privileges to a recipient address.
* @param _recipient The address to grant or revoke Token manager rights.
* @param result Boolean indicating whether to grant (true) or revoke (false) the privilege.
*/
function setTokenManager(address _recipient, bool result) external;
/**
* @dev Grants or revokes permission to call mintTTS to a recipient address.
* @param _recipient The address to grant or revoke permission.
* @param result Boolean indicating whether to grant (true) or revoke (false) the privilege.
*/
function setCallMintTTS(address _recipient, bool result) external;
/**
* @dev Grants or revokes Market admin privileges to a recipient address.
* @param _recipient The address to grant or revoke Market admin rights.
* @param result Boolean indicating whether to grant (true) or revoke (false) the privilege.
*/
function setMarketAdmin(address _recipient, bool result) external;
/**
* @dev Grants or revokes Market manager privileges to a recipient address.
* @param _recipient The address to grant or revoke Market manager rights.
* @param result Boolean indicating whether to grant (true) or revoke (false) the privilege.
*/
function setMarketManager(address _recipient, bool result) external;
/**
* @dev Grants or revokes Stake admin privileges to a recipient address.
* @param _recipient The address to grant or revoke Stake admin rights.
* @param result Boolean indicating whether to grant (true) or revoke (false) the privilege.
*/
function setStakeAdmin(address _recipient, bool result) external;
/**
* @dev Grants or revokes Stake manager privileges to a recipient address.
* @param _recipient The address to grant or revoke Stake manager rights.
* @param result Boolean indicating whether to grant (true) or revoke (false) the privilege.
*/
function setStakeManager(address _recipient, bool result) external;
/**
* @dev Sets or unsets a ban on a recipient address, restricting their access.
* @param _recipient The address to ban or unban.
* @param result Boolean indicating whether to ban (true) or unban (false) the address.
*/
function setBan(address _recipient, bool result) external;
/**
* @dev Returns the amount of TTS available for public sale
* @return _publicsell Returns the amount of TTS available for public sale
*/
function publicsell() external view returns (uint128 _publicsell);
/**
* @dev Returns the authorization level for a given address
* @param recipent user's address
* @return _auth Returns the authorization level
*/
function userConfig(address recipent) external view returns (uint256 _auth);
/**
* @dev Sets the environment variables for normal good ID, value good ID, and market contract address
* @param _marketcontract The address of the market contract
*/
function setEnv(address _marketcontract) external;
/**
* @dev Adds a new mint share to the contract
* @param _share The share structure containing recipient, amount, metric, and chips
* @notice Only callable on the main chain by the DAO admin
* @notice Reduces the left_share by the amount in _share
* @notice Increments the shares_index and adds the new share to the shares mapping
* @notice Emits an e_addShare event with the share details
*/
function addShare(s_share calldata _share, address owner) external;
/**
* @dev Burns the share at the specified index
* @param owner owner of share
*/
function burnShare(address owner) external;
/**
* @dev Mints a share at the specified
*/
function shareMint() external;
/**
* @dev how much cost to buy tts
* @param usdtamount usdt amount
*/
function publicSell(uint256 usdtamount, bytes calldata data) external;
/**
* @dev Withdraws the specified amount from the public sale to the recipient
* @param amount admin tranfer public sell to another address
* @param recipent user's address
*/
function withdrawPublicSell(uint256 amount, address recipent) external;
/**
* @dev Burns the specified value of tokens from the given account
* @param value the amount will be burned
*/
function burn(uint256 value) external;
/// @notice Add a referral relationship
/// @param user The address of the user being referred
/// @param referral The address of the referrer
function setReferral(address user, address referral) external;
/// @notice Stake tokens
/// @param staker The address of the staker
/// @param proofvalue The proof value for the stake
/// @return construct The construct value after staking
function stake(
address staker,
uint128 proofvalue
) external returns (uint128 construct);
/// @notice Unstake tokens
/// @param staker The address of the staker
/// @param proofvalue The proof value for unstaking
function unstake(address staker, uint128 proofvalue) external;
/// @notice Get the DAO admin and referral for a customer
/// @param _customer The address of the customer
/// @return referral The address of the referrer
function getreferral(
address _customer
) external view returns (address referral);
/**
* @dev Permits a share to be transferred
* @param _share The share structure containing recipient, amount, metric, and chips
* @param dealline The deadline for the share transfer
* @param signature The signature of the share transfer
* @param signer The address of the signer
*/
function permitShare(
s_share memory _share,
uint128 dealline,
bytes calldata signature,
address signer
) external;
/**
* @dev Calculates the hash of a share transfer
* @param _share The share structure containing recipient, amount, metric, and chips
* @param owner The address of the owner
* @param leftamount The amount of left share
* @param deadline The deadline for the share transfer
*/
function shareHash(
s_share memory _share,
address owner,
uint128 leftamount,
uint128 deadline,
uint256 nonce
) external pure returns (bytes32);
}
/// @notice Struct for share information
/// @dev Contains information about a share, including the amount of left to unlock, the metric, and the chips
struct s_share {
uint128 leftamount; // unlock amount
uint120 metric; //last unlock's metric
uint8 chips; // define the share's chips, and every time unlock one chips
}
/// @notice Struct for proof information
/// @dev Contains information about a proof, including the contract address and the state
struct s_proof {
address fromcontract; // from which contract
uint256 proofstate; // stake's state amount0 value 128 construct asset
}
"
},
"src/interfaces/IMulticall_v4.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title IMulticall_v4
/// @notice Interface for the Multicall_v4 contract
interface IMulticall_v4 {
/// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
/// @dev The `msg.value` is passed onto all subcalls, even if a previous subcall has consumed the ether.
/// Subcalls can instead use `address(this).value` to see the available ETH, and consume it using {value: x}.
/// @param data The encoded function data for each of the calls to make to this contract
/// @return results The results from each of the calls passed in via data
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
}
"
},
"src/libraries/L_TTSwapUINT256.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.29;
using L_TTSwapUINT256Library for uint256;
/// @notice Converts two uint128 values into a T_BalanceUINT256
/// @param _amount0 The first 128-bit amount
/// @param _amount1 The second 128-bit amount
/// @return balanceDelta The resulting T_BalanceUINT256
function toTTSwapUINT256(uint128 _amount0, uint128 _amount1) pure returns (uint256 balanceDelta) {
assembly ("memory-safe") {
balanceDelta :=
or(shl(128, _amount0), and(0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff, _amount1))
}
}
/// @notice Adds two T_BalanceUINT256 values
/// @param a The first T_BalanceUINT256
/// @param b The second T_BalanceUINT256
/// @return The sum of a and b as a T_BalanceUINT256
function add(uint256 a, uint256 b) pure returns (uint256) {
uint256 res0;
uint256 res1;
uint256 a0;
uint256 a1;
uint256 b0;
uint256 b1;
assembly ("memory-safe") {
a0 := shr(128, a)
a1 := and(0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff, a)
b0 := shr(128, b)
b1 := and(0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff, b)
res0 := add(a0, b0)
res1 := add(a1, b1)
}
require(res0 >= a0 && res0 >= b0 && res1 >= a1 && res1 >= b1 && res1 <type(uint128).max && res0 <type(uint128).max, "TTSwapUINT256: add overflow");
return (res0<<128)+res1;
}
/// @notice Subtracts two T_BalanceUINT256 values
/// @param a The first T_BalanceUINT256
/// @param b The second T_BalanceUINT256
/// @return The difference of a and b as a T_BalanceUINT256
function sub(uint256 a, uint256 b) pure returns (uint256) {
uint256 res0;
uint256 res1;
uint256 a0;
uint256 a1;
uint256 b0;
uint256 b1;
unchecked{
assembly ("memory-safe") {
a0 := shr(128, a)
a1 := and(0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff, a)
b0 := shr(128, b)
b1 := and(0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff, b)
res0 := sub(a0, b0)
res1 := sub(a1, b1)
}}
require(res0 <=a0 && res1<=a1 &&a1>=b1 && a0>=b0, "TTSwapUINT256: sub overflow");
return (res0<<128)+res1;
}
/// @notice Adds the first components and subtracts the second components of two T_BalanceUINT256 values
/// @param a The first T_BalanceUINT256
/// @param b The second T_BalanceUINT256
/// @return The result of (a0 + b0, a1 - b1) as a T_BalanceUINT256
function addsub(uint256 a, uint256 b) pure returns (uint256) {
uint256 res0;
uint256 res1;
uint256 a0;
uint256 a1;
uint256 b0;
uint256 b1;
unchecked{
assembly ("memory-safe") {
a0 := shr(128, a)
a1 := and(0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff, a)
b0 := shr(128, b)
b1 := and(0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff, b)
res0 := add(a0, b0)
res1 := sub(a1, b1)
}}
require(res0 >=a0 && res0>=b0 && res1<=a1 && a1>=b1 && res0<type(uint128).max , "TTSwapUINT256: addsub overflow");
return (res0<<128)+res1;
}
/// @notice Subtracts the first components and adds the second components of two T_BalanceUINT256 values
/// @param a The first T_BalanceUINT256
/// @param b The second T_BalanceUINT256
/// @return The result of (a0 - b0, a1 + b1) as a T_BalanceUINT256
function subadd(uint256 a, uint256 b) pure returns (uint256) {
uint256 res0;
uint256 res1;
uint256 a0;
uint256 a1;
uint256 b0;
uint256 b1;
unchecked{
assembly ("memory-safe") {
a0 := sar(128, a)
a1 := and(0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff, a)
b0 := sar(128, b)
b1 := and(0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff, b)
res0 := sub(a0, b0)
res1 := add(a1, b1)
}}
require(res1 >=a1 && res1>=b1 && res0<=a0 && a0>=b0 && res1<type(uint128).max , "TTSwapUINT256: subadd overflow");
return (res0<<128)+res1;
}
/// @notice Safely converts a uint256 to a uint128
/// @param a The uint256 value to convert
/// @return b converted uint128 value, or 0 if overflow
function toUint128(uint256 a) pure returns (uint128 b) {
b=uint128(a);
require(a==uint256(b) , "TTSwapUINT256: toUint128 overflow");
}
/// @notice Compares the prices of three T_BalanceUINT256 values
/// @param a The first T_BalanceUINT256
/// @param b The second T_BalanceUINT256
/// @param c The third T_BalanceUINT256
/// @return True if the price of a is lower than the prices of b and c, false otherwise
function lowerprice(uint256 a, uint256 b, uint256 c) pure returns (bool) {
return uint256(a.amount0()) * uint256(b.amount1()) * uint256(c.amount1())
> uint256(a.amount1()) * uint256(b.amount0()) * uint256(c.amount0()) ? true : false;
}
/// @notice Performs a multiplication followed by a division
/// @param config The multiplicand
/// @param amount The multiplier
/// @param domitor The divisor
/// @return a The result as a uint128
function mulDiv(uint256 config, uint256 amount, uint256 domitor) pure returns (uint128 a) {
uint256 result;
unchecked {
assembly {
config := mul(config, amount)
result := div(config, domitor)
}
}
return toUint128(result);
}
/// @title L_TTSwapUINT256Library
/// @notice A library for operations on T_BalanceUINT256
library L_TTSwapUINT256Library {
/// @notice Extracts the first 128-bit amount from a T_BalanceUINT256
/// @param balanceDelta The T_BalanceUINT256 to extract from
/// @return _amount0 The extracted first 128-bit amount
function amount0(uint256 balanceDelta) internal pure returns (uint128 _amount0) {
assembly {
_amount0 := shr(128, balanceDelta)
}
}
/// @notice Extracts the second 128-bit amount from a T_BalanceUINT256
/// @param balanceDelta The T_BalanceUINT256 to extract from
/// @return _amount1 The extracted second 128-bit amount
function amount1(uint256 balanceDelta) internal pure returns (uint128 _amount1) {
assembly {
_amount1 := balanceDelta
}
}
/// @notice Extracts the first and second 128-bit amounts from a T_BalanceUINT256
/// @param balanceDelta The T_BalanceUINT256 to extract from
/// @return _amount0 The extracted first 128-bit amount
/// @return _amount1 The extracted second 128-bit amount
function amount01(uint256 balanceDelta) internal pure returns (uint128 _amount0,uint128 _amount1) {
assembly {
_amount0 := shr(128, balanceDelta)
_amount1 := balanceDelta
}
}
/// @notice Calculates amount0 based on a given amount1 and the ratio in balanceDelta
/// @param balanceDelta The T_BalanceUINT256 containing the ratio
/// @param amount1delta The amount1 to base the calculation on
/// @return _amount0 The calculated amount0
function getamount0fromamount1(uint256 balanceDelta, uint128 amount1delta)
internal
pure
returns (uint128 _amount0)
{
return mulDiv(balanceDelta.amount0(), amount1delta, balanceDelta.amount1());
}
/// @notice Calculates amount1 based on a given amount0 and the ratio in balanceDelta
/// @param balanceDelta The T_BalanceUINT256 containing the ratio
/// @param amount0delta The amount0 to base the calculation on
/// @return _amount1 The calculated amount1
function getamount1fromamount0(uint256 balanceDelta
Submitted on: 2025-10-15 11:09:51
Comments
Log in to comment.
No comments yet.