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",
"sources": {
"contracts/token/DSToken.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
import {IDSToken} from "./IDSToken.sol";
import {StandardToken} from "./StandardToken.sol";
import {ISecuritizeRebasingProvider} from "../rebasing/ISecuritizeRebasingProvider.sol";
import {RebasingLibrary} from "../rebasing/RebasingLibrary.sol";
import {TokenLibrary} from "./TokenLibrary.sol";
import {CommonUtils} from "../utils/CommonUtils.sol";
contract DSToken is StandardToken {
// using FeaturesLibrary for SupportedFeatures;
using TokenLibrary for TokenLibrary.SupportedFeatures;
uint256 internal constant DEPRECATED_OMNIBUS_NO_ACTION = 0; // Deprecated, kept for backward compatibility
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(
string calldata _name,
string calldata _symbol,
uint8 _decimals
) public virtual override onlyProxy initializer {
__StandardToken_init();
name = _name;
symbol = _symbol;
decimals = _decimals;
}
/******************************
TOKEN CONFIGURATION
*******************************/
function setFeature(uint8 featureIndex, bool enable) public onlyMaster {
supportedFeatures.setFeature(featureIndex, enable);
}
function setFeatures(uint256 features) public onlyMaster {
supportedFeatures.value = features;
}
function totalIssued() public view returns (uint256) {
ISecuritizeRebasingProvider rebasingProvider = getRebasingProvider();
uint256 tokens = rebasingProvider.convertSharesToTokens(tokenData.totalIssued);
return tokens;
}
/******************************
TOKEN ISSUANCE (MINTING)
*******************************/
/**
* @dev Issues unlocked tokens
* @param _to address The address which is going to receive the newly issued tokens
* @param _value uint256 the value of tokens to issue
* @return true if successful
*/
function issueTokens(
address _to,
uint256 _value /*onlyIssuerOrAbove*/
) public override returns (bool) {
issueTokensCustom(_to, _value, block.timestamp, 0, "", 0);
return true;
}
/**
* @notice Issues tokens with optional locking parameters
* @dev Issues tokens to an address with custom issuance time and optional single lock
* @param _to The address which will receive the newly issued tokens
* @param _value The amount of tokens to issue
* @param _issuanceTime The timestamp when tokens are considered issued
* @param _valueLocked The amount of tokens to be locked (0 for no lock)
* @param _reason The reason for token issuance
* @param _releaseTime The timestamp when locked tokens will be released
* @return bool Returns true if successful
*/
function issueTokensCustom(address _to, uint256 _value, uint256 _issuanceTime, uint256 _valueLocked, string memory _reason, uint64 _releaseTime)
public
virtual
override
returns (
/*onlyIssuerOrAbove*/
bool
)
{
uint256[] memory valuesLocked;
uint64[] memory releaseTimes;
if (_valueLocked > 0) {
valuesLocked = new uint256[](1);
releaseTimes = new uint64[](1);
valuesLocked[0] = _valueLocked;
releaseTimes[0] = _releaseTime;
}
issueTokensWithMultipleLocks(_to, _value, _issuanceTime, valuesLocked, _reason, releaseTimes);
return true;
}
function issueTokensWithMultipleLocks(address _to, uint256 _value, uint256 _issuanceTime, uint256[] memory _valuesLocked, string memory _reason, uint64[] memory _releaseTimes)
public
virtual
override
onlyIssuerOrAbove
returns (bool)
{
ISecuritizeRebasingProvider rebasingProvider = getRebasingProvider();
TokenLibrary.IssueParams memory params = TokenLibrary.IssueParams({
_to: _to,
_value: _value,
_issuanceTime: _issuanceTime,
_valuesLocked: _valuesLocked,
_releaseTimes: _releaseTimes,
_reason: _reason,
_rebasingProvider: rebasingProvider
});
uint256 shares = TokenLibrary.issueTokensCustom(
tokenData,
getCommonServices(),
getLockManager(),
params
);
emit Transfer(address(0), _to, _value);
emit TxShares(address(0), _to, shares, rebasingProvider.multiplier());
checkWalletsForList(address(0), _to);
return true;
}
//*********************
// TOKEN BURNING
//*********************
function burn(address _who, uint256 _value, string calldata _reason) public virtual override onlyIssuerOrTransferAgentOrAbove {
ISecuritizeRebasingProvider rebasingProvider = getRebasingProvider();
uint256 shares = TokenLibrary.burn(tokenData, getCommonServices(), _who, _value, rebasingProvider);
emit Burn(_who, _value, _reason);
emit Transfer(_who, address(0), _value);
emit TxShares(_who, address(0), shares, rebasingProvider.multiplier());
checkWalletsForList(_who, address(0));
}
//*********************
// TOKEN SEIZING
//*********************
function seize(address _from, address _to, uint256 _value, string calldata _reason) public virtual override onlyTransferAgentOrAbove {
ISecuritizeRebasingProvider rebasingProvider = getRebasingProvider();
uint256 shares = rebasingProvider.convertTokensToShares(_value);
TokenLibrary.seize(tokenData, getCommonServices(), _from, _to, _value, shares);
emit Seize(_from, _to, _value, _reason);
emit Transfer(_from, _to, _value);
emit TxShares(_from, _to, shares, rebasingProvider.multiplier());
checkWalletsForList(_from, _to);
}
//*********************
// TRANSFER RESTRICTIONS
//*********************
/**
* @dev Checks whether it can transfer with the compliance manager, if not -throws.
*/
modifier canTransfer(address _sender, address _receiver, uint256 _value) {
getComplianceService().validateTransfer(_sender, _receiver, _value, paused, super.balanceOf(_sender));
_;
}
/**
* @dev override for transfer with modifiers:
* whether the token is not paused (checked in super class)
* and that the sender is allowed to transfer tokens
* @param _to The address that will receive the tokens.
* @param _value The amount of tokens to be transferred.
*/
function transfer(address _to, uint256 _value) public virtual override canTransfer(msg.sender, _to, _value) returns (bool) {
return postTransferImpl(super.transfer(_to, _value), msg.sender, _to, _value);
}
/**
* @dev override for transfer with modifiers:
* whether the token is not paused (checked in super class)
* and that the sender is allowed to transfer tokens
* @param _from The address that will send the tokens.
* @param _to The address that will receive the tokens.
* @param _value The amount of tokens to be transferred.
*/
function transferFrom(address _from, address _to, uint256 _value) public virtual override canTransfer(_from, _to, _value) returns (bool) {
return postTransferImpl(super.transferFrom(_from, _to, _value), _from, _to, _value);
}
function postTransferImpl(bool _superResult, address _from, address _to, uint256 _value) internal returns (bool) {
if (_superResult) {
updateInvestorsBalancesOnTransfer(_from, _to, _value);
}
checkWalletsForList(_from, _to);
return _superResult;
}
//*********************
// WALLET ENUMERATION
//****
function getWalletAt(uint256 _index) public view override returns (address) {
require(_index > 0 && _index <= walletsCount);
return walletsList[_index];
}
function walletCount() public view override returns (uint256) {
return walletsCount;
}
function checkWalletsForList(address _from, address _to) private {
if (super.balanceOf(_from) == 0) {
removeWalletFromList(_from);
}
if (super.balanceOf(_to) > 0) {
addWalletToList(_to);
}
}
function addWalletToList(address _address) private {
//Check if it's already there
uint256 existingIndex = walletsToIndexes[_address];
if (existingIndex == 0) {
//If not - add it
uint256 index = walletsCount + 1;
walletsList[index] = _address;
walletsToIndexes[_address] = index;
walletsCount = index;
}
}
function removeWalletFromList(address _address) private {
//Make sure it's there
uint256 existingIndex = walletsToIndexes[_address];
if (existingIndex != 0) {
uint256 lastIndex = walletsCount;
if (lastIndex != existingIndex) {
//Put the last wallet instead of it (this will work even with 1 wallet in the list)
address lastWalletAddress = walletsList[lastIndex];
walletsList[existingIndex] = lastWalletAddress;
walletsToIndexes[lastWalletAddress] = existingIndex;
}
delete walletsToIndexes[_address];
delete walletsList[lastIndex];
walletsCount = lastIndex - 1;
}
}
//**************************************
// MISCELLANEOUS FUNCTIONS
//**************************************
function balanceOfInvestor(string memory _id) public view override returns (uint256) {
ISecuritizeRebasingProvider rebasingProvider = getRebasingProvider();
uint256 tokens = rebasingProvider.convertSharesToTokens(tokenData.investorsBalances[_id]);
return tokens;
}
function updateInvestorsBalancesOnTransfer(address _from, address _to, uint256 _value) internal {
updateInvestorBalance(_from, _value, CommonUtils.IncDec.Decrease);
updateInvestorBalance(_to, _value, CommonUtils.IncDec.Increase);
}
function updateInvestorBalance(address _wallet, uint256 _value, CommonUtils.IncDec _increase) internal override {
string memory investor = getRegistryService().getInvestor(_wallet);
if (!CommonUtils.isEmptyString(investor)) {
uint256 balance = balanceOfInvestor(investor);
if (_increase == CommonUtils.IncDec.Increase) {
balance += _value;
} else {
balance -= _value;
}
ISecuritizeRebasingProvider rebasingProvider = getRebasingProvider();
uint256 sharesBalance = rebasingProvider.convertTokensToShares(balance);
tokenData.investorsBalances[investor] = sharesBalance;
}
}
function preTransferCheck(address _from, address _to, uint256 _value) public view override returns (uint256 code, string memory reason) {
return getComplianceService().preTransferCheck(_from, _to, _value);
}
function getCommonServices() internal view returns (address[] memory) {
address[] memory services = new address[](2);
services[0] = getDSService(COMPLIANCE_SERVICE);
services[1] = getDSService(REGISTRY_SERVICE);
return services;
}
}
"
},
"contracts/token/IDSToken.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {CommonUtils} from "../utils/CommonUtils.sol";
abstract contract IDSToken is IERC20, Initializable {
event Issue(address indexed to, uint256 value, uint256 valueLocked);
event TxShares(address indexed from, address indexed to, uint256 shares, uint256 multiplier);
event Burn(address indexed burner, uint256 value, string reason);
event Seize(address indexed from, address indexed to, uint256 value, string reason);
event WalletAdded(address wallet);
event WalletRemoved(address wallet);
function initialize(string calldata _name, string calldata _symbol, uint8 _decimals) public virtual;
/******************************
TOKEN ISSUANCE (MINTING)
*******************************/
/**
* @dev Issues unlocked tokens
* @param _to address The address which is going to receive the newly issued tokens
* @param _value uint256 the value of tokens to issue
* @return true if successful
*/
function issueTokens(
address _to,
uint256 _value /*onlyIssuerOrAbove*/
) public virtual returns (bool);
/**
* @dev Issuing tokens from the fund
* @param _to address The address which is going to receive the newly issued tokens
* @param _value uint256 the value of tokens to issue
* @param _valueLocked uint256 value of tokens, from those issued, to lock immediately.
* @param _reason reason for token locking
* @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)
* @return true if successful
*/
function issueTokensCustom(
address _to,
uint256 _value,
uint256 _issuanceTime,
uint256 _valueLocked,
string memory _reason,
uint64 _releaseTime /*onlyIssuerOrAbove*/
) public virtual returns (bool);
function issueTokensWithMultipleLocks(
address _to,
uint256 _value,
uint256 _issuanceTime,
uint256[] memory _valuesLocked,
string memory _reason,
uint64[] memory _releaseTimes /*onlyIssuerOrAbove*/
) public virtual returns (bool);
//*********************
// TOKEN BURNING
//*********************
function burn(
address _who,
uint256 _value,
string calldata _reason /*onlyIssuerOrAbove*/
) public virtual;
//*********************
// TOKEN SIEZING
//*********************
function seize(
address _from,
address _to,
uint256 _value,
string calldata _reason /*onlyIssuerOrAbove*/
) public virtual;
//*********************
// WALLET ENUMERATION
//*********************
function getWalletAt(uint256 _index) public view virtual returns (address);
function walletCount() public view virtual returns (uint256);
//**************************************
// MISCELLANEOUS FUNCTIONS
//**************************************
function isPaused() public view virtual returns (bool);
function balanceOfInvestor(string memory _id) public view virtual returns (uint256);
function updateInvestorBalance(address _wallet, uint256 _value, CommonUtils.IncDec _increase) internal virtual;
function preTransferCheck(address _from, address _to, uint256 _value) public view virtual returns (uint256 code, string memory reason);
}
"
},
"contracts/token/StandardToken.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
import {TokenDataStore} from "../data-stores/TokenDataStore.sol";
import {ISecuritizeRebasingProvider} from "../rebasing/ISecuritizeRebasingProvider.sol";
import {BaseDSContract} from "../utils/BaseDSContract.sol";
import {RebasingLibrary} from "../rebasing/RebasingLibrary.sol";
import {IDSToken} from "./IDSToken.sol";
abstract contract StandardToken is IDSToken, TokenDataStore, BaseDSContract {
event Pause();
event Unpause();
modifier whenNotPaused() {
require(!paused, "Contract is paused");
_;
}
modifier whenPaused() {
require(paused, "Contract is not paused");
_;
}
function __StandardToken_init() public onlyProxy onlyInitializing {
__BaseDSContract_init();
}
function pause() public onlyTransferAgentOrAbove whenNotPaused {
paused = true;
emit Pause();
}
function unpause() public onlyTransferAgentOrAbove whenPaused {
paused = false;
emit Unpause();
}
function isPaused() public view override returns (bool) {
return paused;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256) {
ISecuritizeRebasingProvider rebasingProvider = ISecuritizeRebasingProvider(getDSService(REBASING_PROVIDER));
uint256 shares = tokenData.walletsBalances[_owner];
uint256 tokens = rebasingProvider.convertSharesToTokens(shares);
return tokens;
}
function totalSupply() public view returns (uint256) {
ISecuritizeRebasingProvider rebasingProvider = ISecuritizeRebasingProvider(getDSService(REBASING_PROVIDER));
uint256 totalSupplyTokens = rebasingProvider.convertSharesToTokens(tokenData.totalSupply);
return totalSupplyTokens;
}
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public virtual returns (bool) {
return transferImpl(msg.sender, _to, _value);
}
function transferFrom(
address _from,
address _to,
uint256 _value
) public virtual returns (bool) {
require(_value <= allowances[_from][msg.sender], "Not enough allowance");
allowances[_from][msg.sender] -= _value;
return transferImpl(_from, _to, _value);
}
function transferImpl(
address _from,
address _to,
uint256 _value
) internal returns (bool) {
require(_to != address(0));
ISecuritizeRebasingProvider rebasingProvider = ISecuritizeRebasingProvider(getDSService(REBASING_PROVIDER));
uint256 _shares = rebasingProvider.convertTokensToShares(_value);
require(_shares <= tokenData.walletsBalances[_from]);
tokenData.walletsBalances[_from] -= _shares;
tokenData.walletsBalances[_to] += _shares;
emit Transfer(_from, _to, _value);
emit TxShares(_from, _to, _shares, rebasingProvider.multiplier());
return true;
}
function approve(address _spender, uint256 _value) public returns (bool) {
allowances[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public view returns (uint256) {
return allowances[_owner][_spender];
}
function increaseApproval(address _spender, uint256 _addedValue) public returns (bool) {
allowances[msg.sender][_spender] = allowances[msg.sender][_spender] + _addedValue;
emit Approval(msg.sender, _spender, allowances[msg.sender][_spender]);
return true;
}
function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool) {
uint256 oldValue = allowances[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowances[msg.sender][_spender] = 0;
} else {
allowances[msg.sender][_spender] = oldValue - _subtractedValue;
}
emit Approval(msg.sender, _spender, allowances[msg.sender][_spender]);
return true;
}
}
"
},
"contracts/rebasing/ISecuritizeRebasingProvider.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
/**
* @title ISecuritizeRebasingProvider
* @dev Defines a common interface to get Rebasing multiplier
*/
interface ISecuritizeRebasingProvider {
/**
* @dev Emitted when owner updates multiplier.
* @param oldValue Old multiplier value
* @param newValue New multiplier value
*/
event RebasingRateUpdated(uint256 oldValue, uint256 newValue);
/**
* @dev Proxy Initializer.
* @param _multiplier the initial rebasing multiplier value
* @param _tokenDecimals the token decimals for conversion calculations
*/
function initialize(uint256 _multiplier, uint8 _tokenDecimals) external;
/**
* @dev Set rebasing multiplier. It is expressed with the same decimal numbers as stable coin
*/
function setMultiplier(uint256 _multiplier) external;
/**
* @dev The asset:rebasing multiplier.
* @return The asset:rebasing multiplier.
*/
function multiplier() external view returns (uint256);
/**
* @dev Convert tokens to shares using the current multiplier and token decimals.
* @param _tokens The amount of tokens to convert
* @return shares The equivalent amount in shares
*/
function convertTokensToShares(uint256 _tokens) external view returns (uint256 shares);
/**
* @dev Convert shares to tokens using the current multiplier and token decimals.
* @param _shares The amount of shares to convert
* @return tokens The equivalent amount in tokens
*/
function convertSharesToTokens(uint256 _shares) external view returns (uint256 tokens);
}
"
},
"contracts/rebasing/RebasingLibrary.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
import {IDSToken} from "../token/IDSToken.sol";
library RebasingLibrary {
/*
* @notice Note for auditors regarding rounding logic in rebasing operations.
*
* A finding was raised concerning the "rounding to the nearest" logic in `convertTokensToShares`,
* which could potentially result in a wei being rounded up in favor of the investor.
* We have analyzed and tested different options and our conclusions are the following:
*
* 1. The risk for the protocol of losing a wei over a `convertTokensToShares` operation
* is restricted to tokens with many decimals (17 or 18).
*
* 2. Trying to fix this by rounding down on every operation presents many problems:
* - Users who deposit 1 token immediately see it reflected as less than 1 token (0.99999...),
* which causes confusion and potential complaints.
* - When locking 200 tokens for an investor who holds 500, it should leave 300 tokens
* transferable. Applying a "round down" fix causes this to fail, as a wei is lost
* for the investor who no longer holds the total shares needed to get back their 300 tokens.
* - Similar situations happen with other operations of the protocol, none of which happen
* with the "rounding to the nearest" approach.
*
* 3. Exploiting the wei being rounded up is not economically viable for an attacker. It would
* require thousands of transactions, and the associated gas costs (plus any protocol fees,
* like bridging fees) would exceed any potential gain.
*
* 4. Most of our tokens operate with 6 decimals, while all rebasing operations use 18 decimals
* of precision. For a typical 6-decimal token, taking advantage of this is nearly impossible.
*
* Conclusion: We are leaving the logic as is ("rounding to the nearest integer"). It works well
* in all situations, and while it creates a theoretical risk, it is not practically actionable or
* economically feasible to exploit.
*/
uint256 private constant DECIMALS_FACTOR = 1e18;
/**
* @notice Converts a token amount to a share amount.
* @param _tokens The amount of tokens to convert.
* @param _rebasingMultiplier The current rebasing multiplier, fixed to 18 decimals.
* @param _tokenDecimals The number of decimals of the token.
* @return The corresponding amount of shares.
*/
function convertTokensToShares(
uint256 _tokens,
uint256 _rebasingMultiplier, // should be fixed to 18 decimals
uint8 _tokenDecimals
) internal pure returns (uint256) {
require(_rebasingMultiplier > 0, "Invalid rebasing multiplier");
uint256 shares;
if (_tokenDecimals == 18) {
shares = (_tokens * DECIMALS_FACTOR + _rebasingMultiplier / 2) / _rebasingMultiplier;
} else if (_tokenDecimals < 18) {
uint256 scale = 10**(18 - _tokenDecimals);
shares = (_tokens * scale * DECIMALS_FACTOR + _rebasingMultiplier / 2) / _rebasingMultiplier;
} else {
revert("Token decimals greater than 18 not supported");
}
if (_tokens > 0) {
require(shares > 0, "Shares amount too small");
}
return shares;
}
/**
* @notice Converts a share amount to a token amount.
* @param _shares The amount of shares to convert.
* @param _rebasingMultiplier The current rebasing multiplier, fixed to 18 decimals.
* @param _tokenDecimals The number of decimals of the token.
* @return The corresponding amount of tokens.
*/
function convertSharesToTokens(
uint256 _shares,
uint256 _rebasingMultiplier,
uint8 _tokenDecimals
) internal pure returns (uint256) {
require(_rebasingMultiplier > 0, "Invalid rebasing multiplier");
if (_tokenDecimals == 18) {
return (_shares * _rebasingMultiplier + DECIMALS_FACTOR / 2) / DECIMALS_FACTOR;
} else if (_tokenDecimals < 18) {
uint256 scale = 10**(18 - _tokenDecimals);
return (((_shares * _rebasingMultiplier + DECIMALS_FACTOR / 2) / DECIMALS_FACTOR) + scale / 2) / scale;
} else {
revert("Token decimals greater than 18 not supported");
}
}
}"
},
"contracts/token/TokenLibrary.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
import {ISecuritizeRebasingProvider} from "../rebasing/ISecuritizeRebasingProvider.sol";
import {IDSLockManager} from "../compliance/IDSLockManager.sol";
import {IDSComplianceService} from "../compliance/IDSComplianceService.sol";
import {IDSRegistryService} from "../registry/IDSRegistryService.sol";
import {CommonUtils} from "../utils/CommonUtils.sol";
library TokenLibrary {
event Issue(address indexed to, uint256 value, uint256 valueLocked);
uint256 internal constant COMPLIANCE_SERVICE = 0;
uint256 internal constant REGISTRY_SERVICE = 1;
uint256 internal constant DEPRECATED_OMNIBUS_NO_ACTION = 0; // Deprecated, keep for backwards compatibility
uint256 internal constant DEPRECATED_OMNIBUS_DEPOSIT = 1; // Deprecated, keep for backwards compatibility
uint256 internal constant DEPRECATED_OMNIBUS_WITHDRAW = 2; // Deprecated, keep for backwards compatibility
struct TokenData {
mapping(address wallet => uint256 balance) walletsBalances;
mapping(string investor => uint256 balance) investorsBalances;
uint256 totalSupply;
uint256 totalIssued;
}
struct SupportedFeatures {
uint256 value;
}
struct IssueParams {
address _to;
uint256 _value;
uint256 _issuanceTime;
uint256[] _valuesLocked;
uint64[] _releaseTimes;
string _reason;
ISecuritizeRebasingProvider _rebasingProvider;
}
function setFeature(SupportedFeatures storage supportedFeatures, uint8 featureIndex, bool enable) public {
uint256 base = 2;
uint256 mask = base**featureIndex;
// Enable only if the feature is turned off and disable only if the feature is turned on
if (enable && (supportedFeatures.value & mask == 0)) {
supportedFeatures.value = supportedFeatures.value ^ mask;
} else if (!enable && (supportedFeatures.value & mask >= 1)) {
supportedFeatures.value = supportedFeatures.value ^ mask;
}
}
function issueTokensCustom(
TokenData storage _tokenData,
address[] memory _services,
IDSLockManager _lockManager,
IssueParams memory _params
) public returns (uint256) {
//Check input values
require(_params._to != address(0), "Invalid address");
require(_params._value > 0, "Value is zero");
require(_params._valuesLocked.length == _params._releaseTimes.length, "Wrong length of parameters");
//Check issuance is allowed (and inform the compliance manager, possibly adding locks)
IDSComplianceService(_services[COMPLIANCE_SERVICE]).validateIssuance(_params._to, _params._value, _params._issuanceTime);
uint256 shares = _params._rebasingProvider.convertTokensToShares(_params._value);
_tokenData.totalSupply += shares;
_tokenData.totalIssued += shares;
_tokenData.walletsBalances[_params._to] += shares;
updateInvestorBalance(_tokenData, IDSRegistryService(_services[REGISTRY_SERVICE]), _params._to, shares, CommonUtils.IncDec.Increase);
uint256 totalLocked = 0;
for (uint256 i = 0; i < _params._valuesLocked.length; i++) {
totalLocked += _params._valuesLocked[i];
_lockManager.addManualLockRecord(_params._to, _params._valuesLocked[i], _params._reason, _params._releaseTimes[i]);
}
require(totalLocked <= _params._value, "valueLocked must be smaller than value");
emit Issue(_params._to, _params._value, totalLocked);
return shares;
}
modifier validSeizeParameters(TokenData storage _tokenData, address _from, address _to, uint256 _shares) {
require(_from != address(0), "Invalid address");
require(_to != address(0), "Invalid address");
require(_shares <= _tokenData.walletsBalances[_from], "Not enough balance");
_;
}
function burn(
TokenData storage _tokenData,
address[] memory _services,
address _who,
uint256 _value,
ISecuritizeRebasingProvider _rebasingProvider
) public returns (uint256) {
uint256 sharesToBurn = _rebasingProvider.convertTokensToShares(_value);
require(sharesToBurn <= _tokenData.walletsBalances[_who], "Not enough balance");
// no need to require value <= totalSupply, since that would imply the
// sender's balance is greater than the totalSupply, which *should* be an assertion failure
IDSComplianceService(_services[COMPLIANCE_SERVICE]).validateBurn(_who, _value);
_tokenData.walletsBalances[_who] -= sharesToBurn;
updateInvestorBalance(
_tokenData,
IDSRegistryService(_services[REGISTRY_SERVICE]),
_who,
sharesToBurn,
CommonUtils.IncDec.Decrease
);
_tokenData.totalSupply -= sharesToBurn;
return sharesToBurn;
}
function seize(
TokenData storage _tokenData,
address[] memory _services,
address _from,
address _to,
uint256 _value,
uint256 _shares
)
public
validSeizeParameters(_tokenData, _from, _to, _shares)
{
IDSRegistryService registryService = IDSRegistryService(_services[REGISTRY_SERVICE]);
IDSComplianceService(_services[COMPLIANCE_SERVICE]).validateSeize(_from, _to, _value);
_tokenData.walletsBalances[_from] -= _shares;
_tokenData.walletsBalances[_to] += _shares;
updateInvestorBalance(_tokenData, registryService, _from, _shares, CommonUtils.IncDec.Decrease);
updateInvestorBalance(_tokenData, registryService, _to, _shares, CommonUtils.IncDec.Increase);
}
function updateInvestorBalance(TokenData storage _tokenData, IDSRegistryService _registryService, address _wallet, uint256 _shares, CommonUtils.IncDec _increase) internal {
string memory investor = _registryService.getInvestor(_wallet);
if (!CommonUtils.isEmptyString(investor)) {
uint256 balance = _tokenData.investorsBalances[investor];
if (_increase == CommonUtils.IncDec.Increase) {
balance += _shares;
} else {
balance -= _shares;
}
_tokenData.investorsBalances[investor] = balance;
}
}
}
"
},
"contracts/utils/CommonUtils.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
library CommonUtils {
enum IncDec { Increase, Decrease }
function encodeString(string memory _str) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(_str));
}
function isEqualString(string memory _str1, string memory _str2) internal pure returns (bool) {
return encodeString(_str1) == encodeString(_str2);
}
function isEmptyString(string memory _str) internal pure returns (bool) {
return bytes(_str).length == 0;
}
}
"
},
"node_modules/@openzeppelin/contracts/interfaces/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
"
},
"node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}
"
},
"contracts/data-stores/TokenDataStore.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
import {ServiceConsumerDataStore} from "./ServiceConsumerDataStore.sol";
import {TokenLibrary} from '../token/TokenLibrary.sol';
contract TokenDataStore is ServiceConsumerDataStore {
TokenLibrary.TokenData internal tokenData;
mapping(address owner => mapping(address spender => uint256 allowance)) internal allowances;
mapping(uint256 index => address wallet) internal walletsList;
uint256 internal walletsCount;
mapping(address wallet => uint256 index) internal walletsToIndexes;
// These two variables replace the 2-slot TokenPartitions struct to preserve storage layout
address internal DEPRECATED_PARTITIONS_WALLETS;
address internal DEPRECATED_PARTITIONS_BALANCES;
uint256 public DEPRECATED_CAP;
string public name;
string public symbol;
uint8 public decimals;
TokenLibrary.SupportedFeatures public supportedFeatures;
bool internal paused;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[35] private __gap;
}
"
},
"contracts/utils/BaseDSContract.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
import {ServiceConsumer} from "../service/ServiceConsumer.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
abstract contract BaseDSContract is UUPSUpgradeable, ServiceConsumer {
function __BaseDSContract_init() public onlyProxy onlyInitializing {
__UUPSUpgradeable_init();
__ServiceConsumer_init();
}
/**
* @dev required by the OZ UUPS module
*/
function _authorizeUpgrade(address) internal override onlyMaster {}
/**
* @dev returns proxy ERC1967 implementation address
*/
function getImplementationAddress() external view returns (address) {
return ERC1967Utils.getImplementation();
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function getInitializedVersion() external view returns (uint64) {
return _getInitializedVersion();
}
}
"
},
"contracts/compliance/IDSLockManager.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
abstract contract IDSLockManager {
function initialize() public virtual;
modifier validLock(uint256 _valueLocked, uint256 _releaseTime) {
require(_valueLocked > 0, "Value is zero");
require(_releaseTime == 0 || _releaseTime > uint256(block.timestamp), "Release time is in the past");
_;
}
event Locked(address indexed who, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);
event Unlocked(address indexed who, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);
event HolderLocked(string holderId, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);
event HolderUnlocked(string holderId, uint256 value, uint256 indexed reason, string reasonString, uint256 releaseTime);
/**
* @dev creates a lock record for wallet address
* @param _to address to lock the tokens at
* @param _valueLocked value of tokens to lock
* @param _reason reason for lock
* @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)
* Note: The user MAY have at a certain time more locked tokens than actual tokens
*/
function addManualLockRecord(
address _to,
uint256 _valueLocked,
string calldata _reason,
uint256 _releaseTime /*issuerOrAboveOrToken*/
) public virtual;
/**
* @dev creates a lock record for investor Id
* @param _investor investor id to lock the tokens at
* @param _valueLocked value of tokens to lock
* @param _reasonCode reason code for lock
* @param _reasonString reason for lock
* @param _releaseTime timestamp to release the lock (or 0 for locks which can only released by an unlockTokens call)
* Note: The user MAY have at a certain time more locked tokens than actual tokens
*/
function createLockForInvestor(
string memory _investor,
uint256 _valueLocked,
uint256 _reasonCode,
string calldata _reasonString,
uint256 _releaseTime /*onlyIssuerOrAboveOrToken*/
) public virtual;
/**
* @dev Releases a specific lock record for a wallet
* @param _to address to release the tokens for
* @param _lockIndex the index of the lock to remove
*
* note - this may change the order of the locks on an address, so if iterating the iteration should be restarted.
* @return true on success
*/
function removeLockRecord(
address _to,
uint256 _lockIndex /*issuerOrAbove*/
) public virtual returns (bool);
/**
* @dev Releases a specific lock record for a investor
* @param _investorId investor id to release the tokens for
* @param _lockIndex the index of the lock to remove
*
* note - this may change the order of the locks on an address, so if iterating the iteration should be restarted.
* @return true on success
*/
function removeLockRecordForInvestor(
string memory _investorId,
uint256 _lockIndex /*onlyIssuerOrAbove*/
) public virtual returns (bool);
/**
* @dev Get number of locks currently associated with an address
* @param _who address to get count for
*
* @return number of locks
*
* Note - a lock can be inactive (due to its time expired) but still exists for a specific address
*/
function lockCount(address _who) public view virtual returns (uint256);
/**
* @dev Get number of locks currently associated with a investor
* @param _investorId investor id to get count for
*
* @return number of locks
*
* Note - a lock can be inactive (due to its time expired) but still exists for a specific address
*/
function lockCountForInvestor(string calldata _investorId) public view virtual returns (uint256);
/**
* @dev Get details of a specific lock associated with an address
* can be used to iterate through the locks of a user
* @param _who address to get token lock for
* @param _lockIndex the 0 based index of the lock.
* @return reasonCode the reason code
* @return reasonString the reason for the lock
* @return value the value of tokens locked
* @return autoReleaseTime the timestamp in which the lock will be inactive (or 0 if it's always active until removed)
*
* Note - a lock can be inactive (due to its time expired) but still exists for a specific address
*/
function lockInfo(address _who, uint256 _lockIndex) public view virtual returns (uint256 reasonCode, string memory reasonString, uint256 value, uint256 autoReleaseTime);
/**
* @dev Get details of a specific lock associated with a investor
* can be used to iterate through the locks of a user
* @param _investorId investorId to get token lock for
* @param _lockIndex the 0 based index of the lock.
* @return reasonCode the reason code
* @return reasonString the reason for the lock
* @return value the value of tokens locked
* @return autoReleaseTime the timestamp in which the lock will be inactive (or 0 if it's always active until removed)
*
* Note - a lock can be inactive (due to its time expired) but still exists for a specific address
*/
function lockInfoForInvestor(
string memory _investorId,
uint256 _lockIndex
) public view virtual returns (uint256 reasonCode, string memory reasonString, uint256 value, uint256 autoReleaseTime);
/**
* @dev get total number of transferable tokens for a wallet, at a certain time
* @param _who address to get number of transferable tokens for
* @param _time time to calculate for
*/
function getTransferableTokens(address _who, uint256 _time) public view virtual returns (uint256);
/**
* @dev get total number of transferable tokens for a investor, at a certain time
* @param _investorId investor id
* @param _time time to calculate for
*/
function getTransferableTokensForInvestor(string memory _investorId, uint256 _time) public view virtual returns (uint256);
/**
* @dev pause investor
* @param _investorId investor id
*/
function lockInvestor(
string calldata _investorId /*issuerOrAbove*/
) public virtual returns (bool);
/**
* @dev unpauses investor
* @param _investorId investor id
*/
function unlockInvestor(
string calldata _investorId /*issuerOrAbove*/
) public virtual returns (bool);
/**
* @dev Returns true if paused, otherwise false
* @param _investorId investor id
*/
function isInvestorLocked(string calldata _investorId) public view virtual returns (bool);
/**
* @dev set investor to liquidate only mode
* @param _investorId investor id
* @param _enabled true to enable, false to disable
*/
function setInvestorLiquidateOnly(string memory _investorId, bool _enabled) public virtual returns (bool);
/**
* @dev Returns true if the investor is in liquidate only mode
* @param _investorId investor id
*/
function isInvestorLiquidateOnly(string calldata _investorId) public view virtual returns (bool);
}
"
},
"contracts/compliance/IDSComplianceService.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
abstract contract IDSComplianceService {
uint256 internal constant NONE = 0;
uint256 internal constant US = 1;
uint256 internal constant EU = 2;
uint256 internal constant FORBIDDEN = 4;
uint256 internal constant JP = 8;
string internal constant TOKEN_PAUSED = "Token Paused";
string internal constant NOT_ENOUGH_TOKENS = "Not Enough Tokens";
string internal constant TOKENS_LOCKED = "Tokens Locked";
string internal constant WALLET_NOT_IN_REGISTRY_SERVICE = "Wallet not in registry Service";
string internal constant DESTINATION_RESTRICTED = "Destination restricted";
string internal constant VALID = "Valid";
string internal constant HOLD_UP = "Under lock-up";
string internal constant ONLY_FULL_TRANSFER = "Only Full Transfer";
string internal constant FLOWBACK = "Flowback";
string internal constant MAX_INVESTORS_IN_CATEGORY = "Max Investors in category";
string internal constant AMOUNT_OF_TOKENS_UNDER_MIN = "Amount of tokens under min";
string internal constant AMOUNT_OF_TOKENS_ABOVE_MAX = "Amount of tokens above max";
string internal constant ONLY_ACCREDITED = "Only accredited";
string internal constant ONLY_US_ACCREDITED = "Only us accredited";
string internal constant NOT_ENOUGH_INVESTORS = "Not enough investors";
string internal constant MAX_AUTHORIZED_SECURITIES_EXCEEDED = "Max authorized securities exceeded";
function initialize() public virtual;
function adjustInvestorCountsAfterCountryChange(
string memory _id,
string memory _country,
string memory _prevCountry
) public virtual returns (bool);
//*****************************************
// TOKEN ACTION VALIDATIONS
//*****************************************
function validateTransfer(
address _from,
address _to,
uint256 _value /*onlyToken*/
) public virtual returns (bool);
function validateTransfer(
address _from,
address _to,
uint256 _value, /*onlyToken*/
bool _pausedToken,
uint256 _balanceFrom
) public virtual returns (bool);
function validateIssuance(
address _to,
uint256 _value,
uint256 _issuanceTime /*onlyToken*/
) public virtual returns (bool);
function validateBurn(
address _who,
uint256 _value /*onlyToken*/
) public virtual returns (bool);
function validateSeize(
address _from,
address _to,
uint256 _value /*onlyToken*/
) public virtual returns (bool);
function preIssuanceCheck(address _to, uint256 _value) public view virtual returns (uint256 code, string memory reason);
function preTransferCheck(
address _from,
address _to,
uint256 _value
) public view virtual returns (uint256 code, string memory reason);
function newPreTransferCheck(
address _from,
address _to,
uint256 _value,
uint256 _balanceFrom,
bool _pausedToken
) public view virtual returns (uint256 code, string memory reason);
function preInternalTransferCheck(
address _from,
address _to,
uint256 _value
) public view virtual returns (uint256 code, string memory reason);
function validateIssuanceTime(uint256 _issuanceTime) public view virtual returns (uint256 issuanceTime);
function getComplianceTransferableTokens(
address _who,
uint256 _time,
uint64 _lockTime
) public view virtual returns (uint256);
}
"
},
"contracts/registry/IDSRegistryService.sol": {
"content": "/**
* Copyright 2025 Securitize Inc. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity 0.8.22;
import {CommonUtils} from "../utils/CommonUtils.sol";
abstract contract IDSRegistryService {
function initialize() public virtual;
event DSRegistryServiceInvestorAdded(string investorId, address sender);
event
Submitted on: 2025-10-10 09:04:10
Comments
Log in to comment.
No comments yet.