Skip to content

Commit

Permalink
Add fullfilment (#37)
Browse files Browse the repository at this point in the history
* fullfillment erroring with: Error in fullilment: Error: The fulfiller does not have the balances needed to fulfill.

* added missing files

* order succesfully fulfilled

* dont need to be storing fulfilments

* input chain, tokenid and order path into cli instead of hardcoded

* added different offerer and fulfiller wallets, still erroring

* order failing on InvalidRestrictedOrder

* added get order hash at the end of createListing"

* order succesfully fulfilled

* added missing files

* changed private key names to offerer and buyer

* updated the example.env

* .dist, types and .nvmrc

* fix package.json

* ts formatting

---------

Co-authored-by: Patrick Gallagher <[email protected]>
  • Loading branch information
MrDeadCe11 and pi0neerpat authored Jun 17, 2024
1 parent 45f4007 commit 760b523
Show file tree
Hide file tree
Showing 12 changed files with 1,034 additions and 146 deletions.
23 changes: 10 additions & 13 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
ARB_MAINNET_RPC=
ARB_MAINNET_PK=
ARB_SEPOLIA_RPC=
ARB_SEPOLIA_PK=
ARB_SEPOLIA_OFFERER_PK=
ARB_SEPOLIA_BUYER_PK=
# put the public address of your defaultKey here if you're using the cast wallet
DEFAULT_KEY_PUBLIC_ADDRESS=

ARB_ETHERSCAN_API_KEY=P6DZ75FA2M4WPHNXTIBGKJX4STQP8CGU4G

ARB_SEPOLIA_RPC=
ARB_SEPOLIA_PK=
ARB_ETHERSCAN_API_KEY=
DEFAULT_KEY_PUBLIC_ADDRESS=

# run `anvil` and copy a private key from anvil terminal
ANVIL_ONE=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
ANVIL_RPC=http://127.0.0.1:8545

FOUNDRY_PROFILE=debug

VAULT712_SEPOLIA_ADDRESS=0x05AC7e3ac152012B980407dEff2655c209667E4c
VAULT712_MAINNET_ADDRESS=0x0005AFE00fF7E7FF83667bFe4F2996720BAf0B36
VAULT721_SEPOLIA_ADDRESS=0x05AC7e3ac152012B980407dEff2655c209667E4c
VAULT721_MAINNET_ADDRESS=0x0005AFE00fF7E7FF83667bFe4F2996720BAf0B36
VAULT721_ANVIL_ADDRESS=

OPENSEA_API_KEY=

SIP15_ZONE_ANVIL_ADDRESS=
SIP15_ZONE_ANVIL_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
SIP15_ZONE_SEPOLIA_ADDRESS=0xD658CB9C7626e147c4bd8B8Ef401f1Fb42cA7695
SIP15_ZONE_MAINNET_ADDRESS=

VAULT712_MAINNET_ADAPTER_ADDRESS=
VAULT721_MAINNET_ADAPTER_ADDRESS=
VAULT721_SEPOLIA_ADAPTER_ADDRESS=0xc5736e1F01FB4f013C152B8315019CA20d30FC50
VAULT721_ANVIL_ADAPTER_ADDRESS=
VAULT721_ANVIL_ADAPTER_ADDRESS=0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512

ENCODING_HELPER=
ENCODING_HELPER_MAINNET=
ENCODING_HELPER_ANVIL=
ENCODING_HELPER_SEPOLIA=
ENCODING_HELPER_SEPOLIA=0x672d358f171ae309dc43fc7b5ff3065e8248efe1
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ docs/
lib/

# Typescript
types
types
dist

.nvmrc
700 changes: 700 additions & 0 deletions abis/ERC20.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions abis/EncodeSubstandard5ForEthers.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions abis/Vault721.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions abis/Vault721Adapter.json

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions orders/order-128-1718408958.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"parameters": {
"offerer": "0x941E92c9Eff78a2b7217057752cf938040a59aE9",
"zone": "0xcafc335d2f5bd0e929b4edbf526eb74fa4c49924",
"zoneHash": "0x7f1aff2effced629bfcae4e0a3f749094b2af49ee70357d6bca4e8a2d36eea57",
"startTime": 1718408958,
"endTime": "1718495358",
"orderType": 2,
"offer": [
{
"itemType": 2,
"token": "0x05AC7e3ac152012B980407dEff2655c209667E4c",
"identifierOrCriteria": "128",
"startAmount": "1",
"endAmount": "1"
}
],
"consideration": [
{
"itemType": 1,
"token": "0x8c12A21C8D62d794f78E02aE9e377Abee4750E87",
"identifierOrCriteria": "0",
"startAmount": "1000000",
"endAmount": "1000000",
"recipient": "0x941E92c9Eff78a2b7217057752cf938040a59aE9"
}
],
"totalOriginalConsiderationItems": 1,
"salt": "0x000000000000000000000000000000000000000000000000cb3ba97239090623",
"conduitKey": "0x0000000000000000000000000000000000000000000000000000000000000000",
"counter": "0"
},
"signature": "0xf76030ec389f1f116d3297f58b586092568403b856a56f8696da82d4e088197f858bcc8142a387a3911355bee84751dc009e365484a94e5c7977a16ace75d270"
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@
"scripts": {
"build": "forge build && yarn generate-types",
"coverage": "forge coverage",
"createListing": "tsx script/createListing.ts",
"create-listing": "tsx script/createListing.ts",
"fulfill": "tsx script/fulfillSIP15Order.ts",
"lint:check": "yarn lint:sol && forge fmt --check",
"lint:fix": "sort-package-json && forge fmt && yarn lint:sol --fix",
"lint:sol": "cross-env solhint 'src/**/*.sol' 'test/**/*.sol'",
"test": "FOUNDRY_FUZZ_RUNS=128 FOUNDRY_FUZZ_MAX_TEST_REJECTS=1000000 forge test -vvv --ffi ",
"test:coverage": "forge coverage --report lcov && lcov --ignore-errors unused --remove lcov.info 'node_modules/*' 'script/*' 'test/*' 'src/contracts/for-test/*' 'src/libraries/*' -o lcov.info.pruned && mv lcov.info.pruned lcov.info && genhtml -o coverage-report lcov.info",
"generate-types": "npx typechain --target ethers-v6 'out/SepoliaContracts.s.sol/SepoliaContracts.json' 'out/Vault721Adapter.sol/Vault721Adapter.json' 'out/EncodeSubstandard5ForEthers.sol/EncodeSubstandard5ForEthers.json' --show-stack-traces"
"generate-types": "npx typechain --target ethers-v6 'out/Vault721.sol/Vault721.json' 'out/Vault721Adapter.sol/Vault721Adapter.json' 'out/EncodeSubstandard5ForEthers.sol/EncodeSubstandard5ForEthers.json' --show-stack-traces"
},
"dependencies": {
"@opendollar/contracts": "^0.0.0-c2beba2",
Expand Down
84 changes: 42 additions & 42 deletions script/createListing.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,42 @@
import { BigNumberish, BytesLike, ethers } from "ethers";
import {
Web3Environment
} from "./utils/constants";
import { ethers } from "ethers";
import { Web3Environment } from "./utils/constants";
import { ItemType } from "@opensea/seaport-js/src/constants";
import { CreateOrderInput } from "@opensea/seaport-js/lib/types";
import { convertBigIntsToStrings, getExtraData } from "./utils/helpers";
import fs from "fs";
import path from "path";

const args = process.argv.slice(2);
const chain = args[0];
const vaultId = args[1].toString();
const listingAmount = args[2].toString();


const createSIP15ZoneListing = async (chain: string) => {
const web3Env = new Web3Environment(chain);
const vault721Adapter = web3Env.vault721Adapter;
const encodeSubstandard5Helper = web3Env.encodeSubstandard5Helper;
const vault721AdapterAddress = web3Env.vault721AdapterAddress;
const createSIP15ZoneListing = async (
chain: string,
vaultId: string,
listingAmount: string
) => {
const web3Env = new Web3Environment("offerer", chain);
const vault721Address = web3Env.vault721Address;
const vault721 = web3Env.vault721;
const provider = web3Env.provider;
const sip15ZoneAddress = web3Env.sip15ZoneAddress;
const seaport = web3Env.seaport;
const wallet = web3Env.wallet;

/** @TODO Fill in the token address and token ID of the NFT you want to sell, as well as the price */
///////////////////////////////////////////////////////////////////////////////////////////////////////

let considerationTokenAddress: string =
"0x8c12A21C8D62d794f78E02aE9e377Abee4750E87";
let vaultId: string = "120";
let listingAmount: string = ethers.parseEther("1").toString();



const _comparisonEnums: BigNumberish[] = [4, 5] as BigNumberish[];
const _traitKeys: BytesLike[] = [
ethers.keccak256(ethers.toUtf8Bytes("DEBT")),
ethers.keccak256(ethers.toUtf8Bytes("COLLATERAL")),
];

const _traitValues: BytesLike[] = await vault721Adapter
.getTraitValues(ethers.toBigInt(vaultId), _traitKeys)
.then((array) =>
array.map((e: BytesLike) => {
return e;
})
);

//create encoded substandard 5 data with helper
const extraData = await encodeSubstandard5Helper!.encodeSubstandard5(
_comparisonEnums,
vault721Address,
vault721AdapterAddress,
vaultId,
_traitValues,
_traitKeys
);
listingAmount = ethers.parseEther(listingAmount).toString();
const extraData = await getExtraData(web3Env, vaultId.toString());

// get zone hash by hashing extraData
const zoneHash = ethers.keccak256(extraData);
const timeStamp = (await provider.getBlock("latest"))!.timestamp;
const timeDelay = await vault721.timeDelay();
console.log("ZoneAddress", sip15ZoneAddress);

const createOrderInput: CreateOrderInput = {
offer: [
Expand All @@ -67,25 +49,43 @@ const createSIP15ZoneListing = async (chain: string) => {
consideration: [
{
token: considerationTokenAddress,
amount: ethers.parseEther(listingAmount).toString(),
amount: listingAmount,
},
],
startTime: timeStamp,
endTime: timeStamp,
endTime: (ethers.toBigInt(timeStamp + 86400) + timeDelay).toString(),
zoneHash: zoneHash,
zone: sip15ZoneAddress,
restrictedByZone: true,
};

try {
const conduit = (await seaport.contract.information()).conduitController;
await vault721.setApprovalForAll(await seaport.contract.getAddress(), true);
await vault721.setApprovalForAll(conduit, true);
const { executeAllActions } = await seaport.createOrder(
createOrderInput,
wallet.address
);

const order = await executeAllActions();

const parsedOrder = convertBigIntsToStrings(order);

const outPath = path.join(
`orders/order-${order.parameters.offer[0].identifierOrCriteria}-${order.parameters.startTime}.json`
);
fs.writeFile(outPath, JSON.stringify(parsedOrder, null, 2), (err) => {
if (err) {
console.error(err);
return;
}

console.log("order written to file successfully!");
});
console.log(
"Successfully created a listing with orderHash:",
order.parameters
seaport.getOrderHash(order.parameters)
);
} catch (error) {
console.error("Error in createListing:", error);
Expand All @@ -95,7 +95,7 @@ const createSIP15ZoneListing = async (chain: string) => {
// Check if the module is the main entry point
if (require.main === module) {
// If yes, run the createOffer function
createSIP15ZoneListing("sepolia").catch((error) => {
createSIP15ZoneListing(chain, vaultId, listingAmount).catch((error) => {
console.error("Error in createListing:", error);
});
}
Expand Down
63 changes: 63 additions & 0 deletions script/fulfillSIP15Order.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Web3Environment, ERC20ABI } from "./utils/constants";
import { convertBigIntsToStrings, getExtraData } from "./utils/helpers";
import { OrderWithCounter } from "@opensea/seaport-js/src/types";
import { ethers } from "ethers";
import fs from "fs";
import path from "path";

const args = process.argv.slice(2);
const chain = args[0];
const jsonPath = args[1];

const fulfillSIP15Order = async (chain: string, pathToOrder: string) => {
const web3Env = new Web3Environment("fulfiller", chain);
const seaport = web3Env.seaport;
const wallet = web3Env.wallet;

const _path = path.join(pathToOrder);
const orderWithCounter = JSON.parse(
fs.readFileSync(_path, "utf-8")
) as OrderWithCounter;

const erc20 = new ethers.Contract(
orderWithCounter.parameters.consideration[0].token,
ERC20ABI.abi,
wallet
);
const extraData = await getExtraData(
web3Env,
orderWithCounter.parameters.offer[0].identifierOrCriteria
);

try {
const conduitAddress = (await seaport.contract.information())
.conduitController;
const seaportAddress = await seaport.contract.getAddress();

await erc20.approve(seaportAddress, ethers.MaxUint256);
await erc20.approve(conduitAddress, ethers.MaxUint256);

const { executeAllActions } = await seaport.fulfillOrder({
order: orderWithCounter,
unitsToFill: 1,
extraData: extraData,
exactApproval: true,
});

const fulfillment = await executeAllActions();

console.log("Successfully fulfilled a listing:", fulfillment.to);
} catch (error) {
console.error("Error in fulfillment:", error);
}
};

// Check if the module is the main entry point
if (require.main === module) {
// If yes, run the createOffer function
fulfillSIP15Order(chain, jsonPath).catch((error) => {
console.error("Error in fulfillSIP15ZoneOrder:", error);
});
}

export default fulfillSIP15Order;
Loading

0 comments on commit 760b523

Please sign in to comment.