StockFactoryConveyor
0x483c6cc68f9ef77eb9550e13e93657c0f8b60ea6
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
11,844 bytes
ABI entries
10
5 read · 2 write
License
none
Contract information
- Address
- 0x483c6cc68f9ef77eb9550e13e93657c0f8b60ea6
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0xAb882B959F…317d83d1f5
- Creation tx
- 0x5f42175368…e45fe93d9f
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (5)
MAX_SALT_TRIES() → uint256
factory() → address
findSaltTokenLTQuote(string, string, bytes32, address) → bytes32, address
getTokenBytecode(string, string, address) → bytes
indexer() → address
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "_factory",
"type": "address"
},
{
"internalType": "address",
"name": "_indexer",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "OnlyFactory",
"type": "error"
},
{
"inputs": [],
"name": "SaltSearchFailed",
"type": "error"
},
{
"inputs": [],
"name": "MAX_SALT_TRIES",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "address",
"name": "originalDeployer",
"type": "address"
},
{
"internalType": "address",
"name": "quoteToken",
"type": "address"
}
],
"name": "deployToken",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "predicted",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "factory",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "bytes32",
"name": "baseSalt",
"type": "bytes32"
},
{
"internalType": "address",
"name": "quoteToken",
"type": "address"
}
],
"name": "findSaltTokenLTQuote",
"outputs": [
{
"internalType": "bytes32",
"name": "saltFound",
"type": "bytes32"
},
{
"internalType": "address",
"name": "predicted",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "address",
"name": "quoteToken",
"type": "address"
}
],
"name": "getTokenBytecode",
"outputs": [
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "indexer",
"outputs": [
{
"internalType": "contract IIndexer",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_newIndexer",
"type": "address"
}
],
"name": "setIndexer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
import "./StockToken.sol";
/// @notice Same CREATE2 salt-mining pattern as FactoryConveyor, generalized
/// so the "must sort above the quote asset" check works against whichever
/// stock token a given launch is paired with, instead of a single address
/// fixed at deploy time. One conveyor instance can back launches against any
/// number of different tokenized stocks.
contract StockFactoryConveyor {
address public immutable factory;
uint256 public constant MAX_SALT_TRIES = 1024;
IIndexer public indexer;
error OnlyFactory();
modifier onlyFactory() {
if (msg.sender != factory) revert OnlyFactory();
_;
}
constructor(address _factory, address _indexer) {
factory = _factory;
indexer = IIndexer(_indexer);
}
function setIndexer(address _newIndexer) external onlyFactory {
indexer = IIndexer(_newIndexer);
}
function _tokenInitCode(
string memory name,
string memory symbol,
address quoteToken
) internal view returns (bytes memory) {
return
abi.encodePacked(
type(StockFunToken).creationCode,
abi.encode(name, symbol, factory, address(indexer), quoteToken)
);
}
function _predictCreate2(
bytes32 salt,
bytes32 initCodeHash
) internal view returns (address) {
bytes32 h = keccak256(
abi.encodePacked(bytes1(0xff), address(this), salt, initCodeHash)
);
return address(uint160(uint256(h)));
}
function getTokenBytecode(
string memory name,
string memory symbol,
address quoteToken
) external view returns (bytes memory) {
return _tokenInitCode(name, symbol, quoteToken);
}
/// @notice Brute-forces a salt so the predicted token address sorts
/// above `quoteToken` - the same trick FactoryConveyor uses for WBNB,
/// generalized to any quote asset so the new token always lands as
/// token1 and the quote asset as token0, a consistent ordering the
/// Factory's liquidity/fee logic can rely on.
function findSaltTokenLTQuote(
string memory name,
string memory symbol,
bytes32 baseSalt,
address quoteToken
) external view onlyFactory returns (bytes32 saltFound, address predicted) {
bytes memory initCode = _tokenInitCode(name, symbol, quoteToken);
bytes32 initHash = keccak256(initCode);
uint160 quoteNum = uint160(quoteToken);
for (uint256 i; i < MAX_SALT_TRIES; ) {
bytes32 saltCand = keccak256(abi.encodePacked(baseSalt, i));
address addr = _predictCreate2(saltCand, initHash);
if (uint160(addr) > quoteNum) {
return (saltCand, addr);
}
unchecked {
++i;
}
}
revert SaltSearchFailed();
}
function deployToken(
string memory name,
string memory symbol,
bytes32 salt,
address originalDeployer,
address quoteToken
) external onlyFactory returns (address token, address predicted) {
bytes memory initCode = _tokenInitCode(name, symbol, quoteToken);
bytes32 initHash = keccak256(initCode);
StockFunToken t = new StockFunToken{salt: salt}(
name,
symbol,
factory,
address(indexer),
quoteToken
);
token = address(t);
predicted = _predictCreate2(salt, initHash);
require(token == predicted, "CREATE2 address mismatch");
indexer.emitSaltBruteforced(salt, token);
indexer.emitERC20TokenCreated(token, originalDeployer);
indexer.authorizeAddress(token);
}
}
Chain explorer1881msChain node92ms