Skip to main content

SemiFungiblePositionManager

The SFPM smart contract manages LP position using the ERC1155 interface.

Semifungible Position Manager for Panoptic. Replaces the functionalities of the Nonfungible Position manager, and more. Wraps up to 4-legged Uniswap V3 positions in the ERC1155 non-fungible token interface

Write Methods

initializePool

function initializePool(address token0, address token1, uint24 fee) external nonpayable

Initialized a Uniswap v3 pool in the SemifungiblePositionManager contract

Reverts if already initialized, should be called when a position is created for the first time

Parameters

NameTypeDescription
token0addressThe contract address of token0 of the pool
token1addressThe contract address of token1 of the pool
feeuint24The fee amount of the v3 pool for the specified token pair

mintTokenizedPosition

function mintTokenizedPosition(
uint256 tokenId,
uint128 numberOfContracts,
int48 tickLimits
)
external
payable
returns (
int256 totalAmounts,
int256 totalSwapped
)

Creates a new position containing up to 4 legs wrapped in a ERC1155 token.

Reverts if the user touches an existing leg.

Parameters

NameTypeDescription
tokenIduint256The tokenId of the minted position, which encodes information about up to 4 legs
numberOfContractsuint128The number of contracts minted, expressed in terms of token0
tickLimitsint48LeftRight encoded price slippage limit when minting an ITM position (set to zero for no swapping)

Returns

NameTypeDescription
totalAmountsint256A LeftRight encoded word containing the total amount of token0 and token1 moved to the Uniswap Pool (can be negative)
totalSwappedint256A LeftRight encoded word containing the total amount of token0 and token1 swapped when liquidity was deployed if tickLimits != 0

burnTokenizedPosition

function burnTokenizedPosition(
uint256 tokenId,
uint128 numberOfContracts,
int48 tickLimits
)
external
payable
returns (
int256 totalAmounts,
int256 totalCollected,
int256 totalSwapped
)

Burns a new position containing up to 4 legs wrapped in a ERC1155 token.

Auto-collect all accumulated fees.

Parameters

NameTypeDescription
tokenIduint256The tokenId of the minted position, which encodes information about up to 4 legs
numberOfContractsuint128The number of contracts minted, expressed in terms of token0
tickLimitsint48LeftRight encoded orice slippage when swapping asset at burn step (set to zero for no swapping)

Returns

NameTypeDescription
totalAmountsint256A LeftRight encoded word containing the total amount of token0 and token1 moved to the Uniswap Pool (can be negative)
totalCollectedint256A LeftRight encoded word containing the total amount of token0 and token1 collected as fees
totalSwappedint256A LeftRight encoded word containing the total amount of token0 and token1 swapped at collection if tickLimits != 0

rollPosition

function rollPosition(
uint256 oldTokenId,
uint256 newTokenId
) external payable returns (uint128 numberOfContracts)

Roll a position containing up to 4 legs wrapped in oldTokenId to newTokenId.

Will either i) perform burnTokenizedPosition then mintTokenizedPosition, ii) create a new tokenId that only rolls the touched legs or iii) moves liquidity between pool by calling burn in the mint callback

Parameters

NameTypeDescription
oldTokenIduint256The tokenId of the burnt position
newTokenIduint256The tokenId of the newly minted position

Returns

NameTypeDescription
numberOfContractsuint128The number of contracts minted, expressed in terms of token0

View Methods

getAccountFeesBase

function getAccountFeesBase(
address univ3poolAddress,
address owner,
int24 tickLower,
int24 tickUpper
) external view returns (int128 feesBase0, int128 feesBase1)

Returns the feesBase associated with a given position.

Computes accountFeesBase[keccak256(abi.encodePacked(univ3poolAddress, owner, tickLower, tickUpper))]

feesBase0 is computed as FullMath.mulDiv(feeGrowthInside0X128, legLiquidity, FixedPoint128.Q128)

Parameters

NameTypeDescription
univ3poolAddressaddressThe address of the Uniswap v3 Pool
owneraddressThe address of the account that is queried
tickLowerint24The lower end of the tick range for the position (int24)
tickUpperint24The upper end of the tick range for the position (int24)

Returns

NameTypeDescription
feesBase0int128The feesBase of the position for token0
feesBase1int128The feesBase of the position for token1

getAccountLiquidity

function getAccountLiquidity(
address univ3poolAddress,
address owner,
int24 tickLower,
int24 tickUpper
) external view returns (uint128 liquidity)

Returns the liquidity associated with a given position.

Computes accountLiquidity[keccak256(abi.encodePacked(univ3poolAddress, owner, tickLower, tickUpper))]

Parameters

NameTypeDescription
univ3poolAddressaddressThe address of the Uniswap v3 Pool
owneraddressThe address of the account that is queried
tickLowerint24The lower end of the tick range for the position (int24)
tickUpperint24The upper end of the tick range for the position (int24)

Returns

NameTypeDescription
liquidityuint128The liquidity of the position described by the input parameters

Events

TokenizedPositionBurnt

event TokenizedPositionBurnt(address indexed recipient, uint256 tokenId, uint128 numberOfContracts)

Emitted when a position is burnt

Parameters

NameTypeDescription
recipient indexedaddressundefined
tokenIduint256undefined
numberOfContractsuint128undefined

TokenizedPositionMinted

event TokenizedPositionMinted(address indexed recipient, uint256 tokenId, uint128 numberOfContracts)

Emitted when a position is created

Parameters

NameTypeDescription
recipient indexedaddressundefined
tokenIduint256undefined
numberOfContractsuint128undefined

TokenizedPositionRolled

event TokenizedPositionRolled(address indexed recipient, uint256 oldTokenId, uint256 newTokenId, uint128 numberOfContracts)

Emitted when a position is rolled (ie. burnt and re-deployed)

Parameters

NameTypeDescription
recipient indexedaddressundefined
oldTokenIduint256undefined
newTokenIduint256undefined
numberOfContractsuint128undefined

ABI

SemiFungiblePositionManager ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "_factory",
"type": "address"
},
{
"internalType": "address",
"name": "_WETH9",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "ApprovalForAll",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint128",
"name": "numberOfContracts",
"type": "uint128"
}
],
"name": "TokenizedPositionBurnt",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint128",
"name": "numberOfContracts",
"type": "uint128"
}
],
"name": "TokenizedPositionMinted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "oldTokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "newTokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint128",
"name": "numberOfContracts",
"type": "uint128"
}
],
"name": "TokenizedPositionRolled",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
},
{
"indexed": false,
"internalType": "uint256[]",
"name": "values",
"type": "uint256[]"
}
],
"name": "TransferBatch",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "TransferSingle",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "string",
"name": "value",
"type": "string"
},
{
"indexed": true,
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "URI",
"type": "event"
},
{
"stateMutability": "payable",
"type": "fallback"
},
{
"inputs": [],
"name": "WETH9",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "accounts",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
}
],
"name": "balanceOfBatch",
"outputs": [
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "numberOfContracts",
"type": "uint128"
},
{
"internalType": "int48",
"name": "tickLimits",
"type": "int48"
}
],
"name": "burnTokenizedPosition",
"outputs": [
{
"internalType": "int256",
"name": "transactedAmounts",
"type": "int256"
},
{
"internalType": "int256",
"name": "totalCollected",
"type": "int256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "factory",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "univ3poolAddress",
"type": "address"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "int24",
"name": "tickLower",
"type": "int24"
},
{
"internalType": "int24",
"name": "tickUpper",
"type": "int24"
}
],
"name": "getAccountFeesBase",
"outputs": [
{
"internalType": "int128",
"name": "feesBase0",
"type": "int128"
},
{
"internalType": "int128",
"name": "feesBase1",
"type": "int128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "univ3poolAddress",
"type": "address"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "int24",
"name": "tickLower",
"type": "int24"
},
{
"internalType": "int24",
"name": "tickUpper",
"type": "int24"
}
],
"name": "getAccountLiquidity",
"outputs": [
{
"internalType": "uint128",
"name": "liquidity",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token0",
"type": "address"
},
{
"internalType": "address",
"name": "token1",
"type": "address"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
}
],
"name": "initializePool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "isApprovedForAll",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "numberOfContracts",
"type": "uint128"
},
{
"internalType": "int48",
"name": "tickLimits",
"type": "int48"
}
],
"name": "mintTokenizedPosition",
"outputs": [
{
"internalType": "int256",
"name": "transactedAmounts",
"type": "int256"
},
{
"internalType": "bool",
"name": "hasSwapped",
"type": "bool"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "refundETH",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "oldTokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "newTokenId",
"type": "uint256"
}
],
"name": "rollPosition",
"outputs": [
{
"internalType": "uint128",
"name": "numberOfContracts",
"type": "uint128"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "safeBatchTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amountMinimum",
"type": "uint256"
},
{
"internalType": "address",
"name": "recipient",
"type": "address"
}
],
"name": "sweepToken",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amount0Owed",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amount1Owed",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "uniswapV3MintCallback",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "int256",
"name": "amount0Delta",
"type": "int256"
},
{
"internalType": "int256",
"name": "amount1Delta",
"type": "int256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "uniswapV3SwapCallback",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "amountMinimum",
"type": "uint256"
},
{
"internalType": "address",
"name": "recipient",
"type": "address"
}
],
"name": "unwrapWETH9",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "uri",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]