Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add rarible implementation #36

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c88bab9
add start
gabrielantonyxaviour Oct 31, 2023
b39f6b0
add rarible support
gabrielantonyxaviour Oct 31, 2023
5322620
add rarible testing
gabrielantonyxaviour Oct 31, 2023
c69e8f9
feat: add rarible implementation
gabrielantonyxaviour Oct 31, 2023
9496e80
add type documentation
gabrielantonyxaviour Oct 31, 2023
84a2dd7
add rarible visualizer docs
gabrielantonyxaviour Oct 31, 2023
b610cd8
Document type
SilviaMargaritaOcegueda Oct 31, 2023
d73b4ca
add address book and chain
gabrielantonyxaviour Oct 31, 2023
fe8a42b
add changes
gabrielantonyxaviour Oct 31, 2023
9ecdf4e
deployments fix add new
gabrielantonyxaviour Oct 31, 2023
0a0f862
add utiils
gabrielantonyxaviour Oct 31, 2023
aaaa7a7
add fix
gabrielantonyxaviour Oct 31, 2023
ef0557e
Update type documentation
SilviaMargaritaOcegueda Oct 31, 2023
1e6d6c8
Merge commit
SilviaMargaritaOcegueda Oct 31, 2023
2df1d31
Rename variable
SilviaMargaritaOcegueda Oct 31, 2023
11ed9f3
add
gabrielantonyxaviour Oct 31, 2023
6c0f739
Merge remote-tracking branch 'refs/remotes/origin/main'
gabrielantonyxaviour Oct 31, 2023
84977bf
add fix
gabrielantonyxaviour Oct 31, 2023
2e5b493
add visualize
gabrielantonyxaviour Oct 31, 2023
01aae37
add test
gabrielantonyxaviour Oct 31, 2023
92eea07
add testing data oneinch
gabrielantonyxaviour Oct 31, 2023
d6a0933
feat: add 1inch implementation
gabrielantonyxaviour Oct 31, 2023
8955163
fix: change verifying contract
gabrielantonyxaviour Oct 31, 2023
5ff197c
fix: add type for visualize
gabrielantonyxaviour Oct 31, 2023
336ea73
fix: fusion
gabrielantonyxaviour Oct 31, 2023
a9577db
fix: 1inch fusion type
gabrielantonyxaviour Oct 31, 2023
7410a50
add one inch test fix
gabrielantonyxaviour Nov 14, 2023
6e7341a
merge rarible
gabrielantonyxaviour Nov 14, 2023
f2caf39
remove 1inch
gabrielantonyxaviour Nov 14, 2023
d43abed
add rarible test fix
gabrielantonyxaviour Nov 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
logs
*.log
npm-debug.log*
yarn.lock
package-lock.json

# Runtime data
pids
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
},
"devDependencies": {
"@types/jest": "^29.5.0",
"eslint": "^8.36.0",
"eslint-config-prettier": "^8.7.0",
"jest": "^29.5.0",
"prettier": "^2.8.4",
"ts-jest": "^29.0.5",
"eslint": "^8.36.0",
"typescript": "^5.0.2"
},
"dependencies": {
Expand Down
45 changes: 45 additions & 0 deletions src/types/rarible.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BytesLike } from "ethers";

/**
* @dev all types are taken from rarible contracts
* BigNumberish is casted to string as the EIP-712 doesn't have BigInt (all BigInt will be transformed with .toString())
* @see https://github.com/rarible/protocol-contracts/blob/master/exchange-v2/contracts/libraries/LibOrder.sol#L21
*/

/** Type for Asset Type */
export type AssetType = {
/** Asset type, ETH, ERC20, ERC721, ERC1155 etc */
assetClass: BytesLike;
/** Asset address and tokenId encoded */
data: BytesLike;
};

/** Type for Asset */
export type Asset = {
/** Type for Asset Type */
assetType: AssetType;
/** Amount of tokens or value of the order */
value: string;
};

/** Type for order */
export type RaribleOrder = {
/** Maker of the order */
maker: string;
/** Asset of the maker */
makeAsset: Asset;
/** Taker of the order */
taker: string;
/** Asset of the taker */
takeAsset: Asset;
/** Starting timestamp of the order */
start: string;
/** Ending timestamp of the order */
end: string;
/** Order salt */
salt: string;
/** Type of the order in Bytes4 */
dataType: BytesLike;
/** Order metadata */
data: BytesLike;
};
10 changes: 8 additions & 2 deletions src/visualizer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,33 @@ import { PermitMessage } from "../types";
import { SeaPortPayload } from "../types/seaport";
import { BlurIoOrder } from "../types/blur";
import { LooksrareMakerOrderWithEncodedParams } from "../types/looksrare";
import { LooksRareV2MakerOrder } from "../types/looksrare-v2";
import { RaribleOrder } from "../types/rarible";

import blurIo from "./blur-io";
import erc20Permit from "./erc20-permit";
import looksrare from "./looksrare";
import looksrareV2 from "./looksrare-v2";
import rarible from "./rarible";
import seaport from "./seaport";
import { Domain, VisualizationResult } from "../types/visualizer";
import { WizardError } from "../utils";
import { LooksRareV2MakerOrder } from "../types/looksrare-v2";

export enum PROTOCOL_ID {
OPENSEA_SEAPORT = "OPENSEA_SEAPORT",
LOOKSRARE_EXCHANGE = "LOOKSRARE_EXCHANGE",
LOOKSRARE_EXCHANGE_V2 = "LOOKSRARE_EXCHANGE_V2",
BLUR_IO_MARKETPLACE = "BLUR_IO_MARKETPLACE",
ERC20_PERMIT = "ERC20_PERMIT",
RARIBLE = "EXCHANGE",
}

export const getProtocolId = (domain: Domain): PROTOCOL_ID | undefined => {
if (seaport.isCorrectDomain(domain)) return PROTOCOL_ID.OPENSEA_SEAPORT;
if (blurIo.isCorrectDomain(domain)) return PROTOCOL_ID.BLUR_IO_MARKETPLACE;
if (looksrareV2.isCorrectDomain(domain)) return PROTOCOL_ID.LOOKSRARE_EXCHANGE_V2;
if (looksrare.isCorrectDomain(domain)) return PROTOCOL_ID.LOOKSRARE_EXCHANGE;

if (rarible.isCorrectDomain(domain)) return PROTOCOL_ID.RARIBLE;
return;
};

Expand Down Expand Up @@ -55,6 +58,9 @@ export default async function visualize<T extends object>(
case PROTOCOL_ID.BLUR_IO_MARKETPLACE:
return blurIo.visualize(message as BlurIoOrder, domain);

case PROTOCOL_ID.RARIBLE:
return rarible.visualize(message as RaribleOrder, domain);

default:
if (erc20Permit.isERC20Permit(message)) {
return erc20Permit.visualize(message as PermitMessage, domain);
Expand Down
109 changes: 109 additions & 0 deletions src/visualizer/rarible/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* @see https://docs.rarible.org/developers/protocol/order-types-v2
*/

import { ethers } from "ethers";
import { PROTOCOL_ID } from "..";
import { ASSET_TYPE, AssetInOut } from "../../types";
import { RaribleOrder } from "../../types/rarible";
import { Domain, EIP712Protocol, VisualizationResult } from "../../types/visualizer";
import { WizardError, getPaymentAssetType } from "../../utils";
import {
buildAssetERC1155,
buildAssetERC20,
buildAssetERC721,
buildAssetETH,
getAssetClass,
} from "./utils";

const { ERC1155, ERC721 } = ASSET_TYPE;

/**
* @dev checks if the chain and the signer of the transaction is valid
*/
export const isCorrectDomain = (domain: Domain) => {
return (
supportedChains.includes(Number(domain.chainId)) &&
addressesBook.includes(domain.verifyingContract.toLocaleLowerCase())
);
};

/**
*
* @param message The decoded message of the rarible order to be visualized
* @param domain Domain of the rarible order
* @returns Returns the visualization result in the ERC6865 format
*/
export const visualize = (message: RaribleOrder, domain: Domain): VisualizationResult => {
if (!isCorrectDomain(domain)) throw new Error("wrong rarible domain");
let assetIn: AssetInOut[];
let assetOut: AssetInOut[];

/** Check the type of the taker asset to build AssetIn */
if (message.takeAsset.assetType.assetClass === getAssetClass("ETH")) {
assetIn = buildAssetETH(message.takeAsset);
} else if (message.takeAsset.assetType.assetClass === getAssetClass("ERC20")) {
assetIn = buildAssetERC20(message.takeAsset);
} else if (message.takeAsset.assetType.assetClass === getAssetClass("ERC721")) {
assetIn = buildAssetERC721(message.takeAsset);
} else if (message.takeAsset.assetType.assetClass === getAssetClass("ERC1155")) {
assetIn = buildAssetERC1155(message.takeAsset);
} else {
throw new WizardError(
`unknown rarible asset class: ${message.takeAsset.assetType.assetClass}`
);
}

/** Check the type of the maker asset to build AssetOut */
if (message.makeAsset.assetType.assetClass === getAssetClass("ETH")) {
assetOut = buildAssetETH(message.makeAsset);
} else if (message.makeAsset.assetType.assetClass === getAssetClass("ERC20")) {
assetOut = buildAssetERC20(message.makeAsset);
} else if (message.makeAsset.assetType.assetClass === getAssetClass("ERC721")) {
assetOut = buildAssetERC721(message.makeAsset);
} else if (message.makeAsset.assetType.assetClass === getAssetClass("ERC1155")) {
assetOut = buildAssetERC1155(message.makeAsset);
} else {
throw new WizardError(
`unknown rarible asset class: ${message.makeAsset.assetType.assetClass}`
);
}

/** Returns the ERC6865 format of the order */
return {
protocol: PROTOCOL_ID.RARIBLE,
assetsIn: assetIn,
assetsOut: assetOut,
liveness: {
from: Number(message.start),
to: Number(message.end),
},
approvals: [],
};
};

/**
* @see https://docs.rarible.org/reference/contract-addresses/
*/
const supportedChains = [
1, //Ethereum
5, //Goerli
137, //Polygon
80001, //Mumbai
];

/**
* @see https://docs.rarible.org/reference/contract-addresses/
*/
const addressesBook = [
"0x9757F2d2b135150BBeb65308D4a91804107cd8D6", // Mainnet Exchange
"0x02afbD43cAD367fcB71305a2dfB9A3928218f0c1", // Goerli Exchange
"0x835131b455778559CFdDd358eA3Fc762728F4E3e", // Polygon Exchange
"0x4F05968D804902dd827Dd0F4fB37Ccc3071C4Bb5", // Mumbai Exchange
].map((e) => e.toLocaleLowerCase());

const rarible: EIP712Protocol<RaribleOrder> = {
isCorrectDomain,
visualize,
};
export default rarible;
88 changes: 88 additions & 0 deletions src/visualizer/rarible/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { keccak256, toUtf8Bytes, AbiCoder } from "ethers";
import { ZERO_ADDRESS } from "../../utils";
import { ASSET_TYPE, AssetInOut } from "../../types";
import { Asset } from "../../types/rarible";

/**
*
* @param assetType Receives the asset type like ETH, ERC20, ERC721 etc.
* @returns assetClass selector in bytes4 format
*/
export function getAssetClass(assetType: string): string {
return keccak256(toUtf8Bytes(assetType)).slice(0, 10);
}

/**
*
* @param asset Converts ETH asset to ERC6865 standard
* @returns Returns AssetInOut in the ERC6865 format
*/
export function buildAssetETH(asset: Asset): AssetInOut[] {
return [
{
type: ASSET_TYPE.NATIVE,
amounts: [asset.value],
address: ZERO_ADDRESS,
},
];
}

/**
*
* @param asset Converts ERC20 asset to ERC6865 standard
* @returns Returns AssetInOut in the ERC6865 format
*/
export function buildAssetERC20(asset: Asset): AssetInOut[] {
const abiCoder = AbiCoder.defaultAbiCoder();

const address = abiCoder.decode(["address"], asset.assetType.data)[0];
return [
{
type: ASSET_TYPE.ERC20,
amounts: [asset.value],
address: address.toLowerCase(),
},
];
}

/**
*
* @param asset Converts ERC721 asset to ERC6865 standard
* @returns Returns AssetInOut in the ERC6865 format
*/
export function buildAssetERC721(asset: Asset): AssetInOut[] {
const abiCoder = AbiCoder.defaultAbiCoder();

const decodedData = abiCoder.decode(["address", "uint256"], asset.assetType.data);
const address = decodedData[0];
const tokenId = decodedData[1];
return [
{
type: ASSET_TYPE.ERC721,
amounts: ["1"],
id: tokenId.toString(),
address: address.toLowerCase(),
},
];
}

/**
*
* @param asset Converts ERC1155 asset to ERC6865 standard
* @returns Returns AssetInOut in the ERC6865 format
*/
export function buildAssetERC1155(asset: Asset): AssetInOut[] {
const abiCoder = AbiCoder.defaultAbiCoder();

const decodedData = abiCoder.decode(["address", "uint256"], asset.assetType.data);
const address = decodedData[0];
const tokenId = decodedData[1];
return [
{
type: ASSET_TYPE.ERC1155,
amounts: [asset.value],
id: tokenId.toString(),
address: address.toLowerCase(),
},
];
}
79 changes: 79 additions & 0 deletions test/visualizer/rarible/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { getAssetClass } from "../../../src/visualizer/rarible/utils";

const raribleERC20InERC1155Out = {
maker: "0x000075B45Dff84C00Cf597d5C3E766108CeA0000".toLowerCase(),
makeAsset: {
assetType: {
assetClass: getAssetClass("ERC1155"),
data: "0x000000000000000000000000d9145cce52d386f254917e481eb44e9943f391380000000000000000000000000000000000000000000000000000000000000045",
},
value: "6",
},
taker: "0xd8b934580fcE35a11B58C6D73aDeE468a2833fa8".toLowerCase(),
takeAsset: {
assetType: {
assetClass: getAssetClass("ERC20"),
data: "0x000000000000000000000000f8e81D47203A594245E36C48e151709F0C19fBe8".toLowerCase(),
},
value: "10000000000000000000",
},
start: "1698643839",
end: "1798843839",
salt: "0",
dataType: "0x",
data: "0x",
};

const raribleETHInERC721Out = {
maker: "0x000075B45Dff84C00Cf597d5C3E766108CeA0000".toLowerCase(),
makeAsset: {
assetType: {
assetClass: getAssetClass("ERC721"),
data: "0x000000000000000000000000d9145cce52d386f254917e481eb44e9943f391380000000000000000000000000000000000000000000000000000000000000045",
},
value: "1",
},
taker: "0xd8b934580fcE35a11B58C6D73aDeE468a2833fa8".toLowerCase(),
takeAsset: {
assetType: {
assetClass: getAssetClass("ETH"),
data: "0x0000000000000000000000000000000000000000",
},
value: "100000000000000000",
},
start: "1698643839",
end: "1798843839",
salt: "0",
dataType: "0x",
data: "0x",
};

const raribleERC1155InETHOut = {
maker: "0x000075B45Dff84C00Cf597d5C3E766108CeA0000".toLowerCase(),
makeAsset: {
assetType: {
assetClass: getAssetClass("ETH"),
data: "0x0000000000000000000000000000000000000000",
},
value: "100000000000000000",
},
taker: "0xd8b934580fcE35a11B58C6D73aDeE468a2833fa8".toLowerCase(),
takeAsset: {
assetType: {
assetClass: getAssetClass("ERC1155"),
data: "0x000000000000000000000000d9145cce52d386f254917e481eb44e9943f391380000000000000000000000000000000000000000000000000000000000000045",
},
value: "6",
},
start: "1698643839",
end: "1798843839",
salt: "0",
dataType: "0x",
data: "0x",
};

Object.freeze(raribleERC1155InETHOut);
Object.freeze(raribleERC20InERC1155Out);
Object.freeze(raribleETHInERC721Out);

export { raribleERC1155InETHOut, raribleERC20InERC1155Out, raribleETHInERC721Out };
Loading