This project allows users to deploy custom derivative contracts to any chain, speculating on any asset, with any collateral. Palmcivet's Custom Derivatives utilizes Chainlink CCIP, Automation, Data Feeds, and Data Streams. There are two versions of this project - V1 uses Data Feeds and V2 uses Data Streams. Both of these Chainlink services are used for securing the price of the underlying asset in the derivative contract, but in slightly different ways - Data Feeds is a push based oracle and Data Streams is a pull based oracle.
Derivatives agreements have long been a popular investment vehicle and potential usecase for smart contracts. With Palmcivet's Custom Derivatives; anyone can deploy a derivative agreement, specifying the following parameters:
- Underlying Asset - The price of this asset is what will be speculated on.
- Strike Price - The price the actual price of the underlying asset will be compared to.
- Settlement Time - The time the actual price of the underlying asset will be compared to the strike price.
- Collateral Asset - The asset both parties put forward to speculate on the underlying asset with.
- Collateral Amount - The amount of the collateral asset both parties put forward.
- Long or Short Position - The deploying party must specify their long or short position. The counterparty will take the opposite.
Users interact with a Derivative Factory contract to deploy their custom contract. When a user deploys their custom derivative contract, the Derivative Factory contract registers it with Chainlink Automation. Custom Logic Automation is used for comparing the price of the underlying asset against the specified strike price and paying out the collateral deposited by both parties to the party with the winning long or short position when the settlement time is reached. A 2% fee is taken from the total collateral and sent to a developer address.
The contract can be cancelled if both parties agree. If one party requests a cancellation, but the other party doesn't want one; the agreement will continue as originally specified. When both parties agree to a cancellation, they will both receive their full deposits back.
If one party deposits and the other doesn't, when the settlement time is reached, the depositing party can withdraw their full deposit.
As mentioned above there are two versions of this project, each utilizing a different Chainlink service for securing the price of the underlying asset - Data Feeds for V1 and Data Streams for V2.
V1 uses CCIP to allow users to deploy a custom derivative to their chain of choice. It achieves this with a Factory Sender contract on Avalanche Fuji where the user inputs their specifications including the chain of their choice, and a Factory Receiver contract on the chain of their choice which deploys their custom derivative contract and registers its settlement with Chainlink Automation.
latestRoundData()
is called on the AggregatorV3Interface
(the address of which would have been specified by the user as the underlying asset on deployment) to retrieve the price of the underlying asset at settlement time.
My original intention when starting the development of this project was to use only Data Streams to secure the underlying asset's price and also use CCIP to allow users to deploy to their chain of choice. When starting development I was under the impression Data Streams testnet access was restricted and so built V1 with Data Feeds in place of where Data Streams was intended. It turned out testnet access for Data Streams was not restricted and after implementing Data Streams I realised that unfortunately it was not available on a CCIP compatible testnet. That is the reason there are two versions of this project currently. When Data Streams is on a CCIP supported network, the option to deploy to a choice of chains through CCIP with Data Streams securing the underlying asset's price will be available.
Chainlink Custom Logic Automation is once again used in this version with the Data Streams StreamsLookup
revert error emitted in the checkUpkeep()
function. The checkCallback()
function checks the data in the emitted error, passing it to performUpkeep()
which retrieves the price and settles the contract.
UPDATE: The CCIP Masterclass Module #3 showed that Arbitrum Sepolia (the only chain with Data Streams available) is now CCIP compatible, so I have begun integrating CCIP into V2.
I also ended up doing a Polygon zkEVM Edition. Although as Chainlink services were unavailable on this chain, I was unable to implement Chainlink features.
Please provide a .env
file that includes a $PRIVATE_KEY
and RPC URLs for $CHAIN_A
and $CHAIN_B
.
First deploy the Factory Sender contract on Chain A with the following command:
forge script script/v1-data-feeds/DeployFactorySender.s.sol --rpc-url $CHAIN_A --private-key $PRIVATE_KEY --broadcast
Then deploy the Factory Receiver contract on Chain B:
forge script script/v1-data-feeds/DeployFactoryReceiver.s.sol --rpc-url $CHAIN_B --private-key $PRIVATE_KEY --broadcast
Please provide $ARBITRUM_SEPOLIA_RPC_URL
to your .env file.
Deploy the Derivative Factory contract with the following command:
forge script script/v2-data-streams/DeployDerivativeFactoryV2.s.sol --private-key $PRIVATE_KEY --rpc-url $ARBITRUM_SEPOLIA_RPC_URL --broadcast
The Mock USDC contract that was used for testing purposes can be deployed with the following command:
forge script script/DeployMockUSDC.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast
Factory Sender contract on Avalanche Fuji
Factory Receiver contract on Ethereum Sepolia
Tx initiated on Avalanche Fuji
Successful CCIP Tx deploying a custom derivative
Tx on Sepolia deploying a custom derivative
Automation paying out to the winning position Tx
Derivative Factory contract deployed on Arbitrum Sepolia
Automation paying out to winning position using Data Streams Tx
The /frontend
directory contains a basic frontend built with Next.js for deploying custom derivative contracts and depositing collateral.
Make sure to run npm i
.
To npm run dev
inside the /frontend
directory, you will need to provide the following environment variables to /frontend/utils/constants.js
:
ETHERSCAN_API_KEY
SEPOLIA_RPC_URL
ARBISCAN_API_KEY
This project is licensed under the MIT License.