Methods Overview
- makeOffer β Lock your sell-asset into escrow and publish an OTC offer to receive your desired buy-asset.
1. makeOffer
function makeOffer(
Asset calldata depositAsset,
Asset calldata withdrawalAsset,
OfferStruct calldata offer
) external;
What it does:
You deposit your chosen asset (depositAsset) into escrow and create an offer for others to swap their asset (withdrawalAsset) with you. On success, it emits a CreatedOffer event including your new offerId.
Tip: The deposit is locked immediately. Use the returned offerId to track or cancel your offer later.
Parameters
| Name | Type | Description |
|---|---|---|
depositAsset | Asset | The asset youβre selling (ERC20/ERC721/ERC1155); moved into escrow. |
withdrawalAsset | Asset | The asset you want to receive in exchange. |
offer | OfferStruct | Your trading terms: pricing, access control, expiry, timelock, and off-chain communication links. |
Asset Structure
interface Asset {
assetType: AssetType; // ERC20=1, ERC721=2, ERC1155=3
assetAddress: string; // token or NFT contract address
amount: BigNumber; // qty for ERC20/ERC1155; 1 for ERC721
tokenId: BigNumber; // token ID for ERC721/ERC1155; 0 for ERC20
assetPrice: AssetPrice; // only for DynamicPricing
}
interface AssetPrice {
priceFeedAddress: string; // e.g., Chainlink feed
offerMaximumPrice: BigNumber; // max rate (in withdrawalAsset decimals)
offerMinimumPrice: BigNumber; // min rate
}
OfferStruct Structure
interface OfferStruct {
takingOfferType: TakingOfferType; // PartialOffer=1 or BlockOffer=2
offerPrice: OfferPrice; // Fixed or Dynamic pricing
specialAddresses: string[]; // restrict to these takers (empty = public)
authorizationAddresses:string[]; // same as above
expiryTimestamp: number; // when offer expires (unix sec)
timelockPeriod: number; // seconds before it can be taken
terms: string; // URL/IPFS to off-chain terms
commsLink: string; // chat/email link
}
interface OfferPrice {
offerPricingType: OfferPricingType; // FixedPricing=1 or DynamicPricing=2
unitPrice: BigNumber; // price per 1 depositAsset (Fixed)
percentage: BigNumber; // adjust unitPrice by this %
percentageType: PercentageType; // Plus=1 or Minus=2
}
Event Emitted
event CreatedOffer(
address indexed maker,
uint256 indexed offerId,
DotcOffer dotcOffer
);
maker: your addressofferId: unique ID of your new offerdotcOffer: the on-chain record of all your offer details
Possible Errors
| Error | When You Might See It |
|---|---|
ZeroAddressPassed() | You passed a zero address for token, feed, or link. |
IncorrectPercentage(uint256) | Your percentage >100% in offer.offerPrice. |
OfferHelper: OfferExpired | expiryTimestamp is in the past or β€ now + timelockPeriod. |
AssetHelper: InsufficientAssetOwner | You lack balance/allowance (ERC20) or ownership/approval (NFT). |
SafeTransferLib: TransferFailed | Token transfer to escrow failed (e.g. missing approval). |
Usage Tutorial
Example in TypeScript & Ethers.js
Copy-paste into makeOffer.ts, install ethers, then npx ts-node makeOffer.ts.
Prerequisites
- Node.js β₯16 & npm/yarn
- Netowrk RPC endpoint (e.g.
https://polygon-rpc.com/for polygon) - Wallet with enough depositAsset tokens approved
1. Setup & Connect
import { ethers } from "ethers";
const RPC_URL = "https://polygon-rpc.com"; // use RPC accroding to your network
const PRIVATE_KEY = "YOUR_PRIVATE_KEY";
const DOTC_ADDRESS = ethers.getAddress("0x22593b8749A4e4854C449c30054Bb4D896374fa1");
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
// Minimal ABI for makeOffer + event
const ABI = [
"function makeOffer((uint8,address,uint256,uint256,(address,uint256,uint256)),(uint8,address,uint256,uint256,(address,uint256,uint256)),(uint8,(uint8,uint256,uint256,uint8),address[],address[],uint256,uint256,string,string))",
"event CreatedOffer(address indexed maker, uint256 indexed offerId, tuple(address,uint8,(uint8,address,uint256,uint256),uint256,uint256,string,string) dotcOffer)"
];
const dotc = new ethers.Contract(DOTC_ADDRESS, ABI, wallet);
2. Define Your Offer
// Replace TOKEN_A and TOKEN_B with actual addresses
const TOKEN_A = "0xYourTokenA";
const TOKEN_B = "0xYourTokenB";
// 2a) Deposit: 100 of TOKEN_A (18 decimals)
const depositAsset = {
assetType: 1, // ERC20
assetAddress: TOKEN_A,
amount: ethers.utils.parseUnits("100.0", 18),
tokenId: 0,
assetPrice: {
priceFeedAddress: ethers.constants.AddressZero,
offerMaximumPrice: ethers.constants.Zero,
offerMinimumPrice: ethers.constants.Zero,
},
};
// 2b) Withdrawal: 200 of TOKEN_B (6 decimals)
const withdrawalAsset = {
assetType: 1,
assetAddress: TOKEN_B,
amount: ethers.utils.parseUnits("200.0", 6),
tokenId: 0,
assetPrice: {
priceFeedAddress: ethers.constants.AddressZero,
offerMaximumPrice: ethers.constants.Zero,
offerMinimumPrice: ethers.constants.Zero,
},
};
// 2c) Terms: FixedPricing 2 TOKEN_B per 1 TOKEN_A
const offer = {
takingOfferType: 1, // PartialOffer
offerPrice: {
offerPricingType: 1, // FixedPricing
unitPrice: ethers.utils.parseUnits("2.0", 6),
percentage: ethers.constants.Zero,
percentageType: 0, // NoType
},
specialAddresses: [],
authorizationAddresses: [],
expiryTimestamp: Math.floor(Date.now()/1000) + 3600, // +1h
timelockPeriod: 0,
terms: "",
commsLink: ""
};
3. Submit & Listen
async function run() {
console.log("π‘ Submitting makeOffer...");
const tx = await dotc.makeOffer(depositAsset, withdrawalAsset, offer);
console.log("π Tx hash:", tx.hash);
const receipt = await tx.wait();
for (const ev of receipt.events ?? []) {
if (ev.event === "CreatedOffer") {
console.log("β
Offer created!", {
maker: ev.args![0],
offerId: ev.args![1].toString()
});
}
}
}
run().catch(console.error);
4. Run It
npm install ethers
npx ts-node makeOffer.ts
.png)