Skip to content

Commit

Permalink
Merge branch 'main' into raribleIngestor
Browse files Browse the repository at this point in the history
  • Loading branch information
s29papi authored Jul 25, 2024
2 parents 1d8fee4 + 23730e5 commit 322d567
Show file tree
Hide file tree
Showing 11 changed files with 579 additions and 15 deletions.
1 change: 1 addition & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ jobs:
- name: Run Tests
env:
ALCHEMY_API_KEY: ${{ secrets.ALCHEMY_API_KEY }}
SIMULATE_DURING_TESTS: ${{ vars.SIMULATE_DURING_TESTS }}
run: yarn install --userconfig=/dev/null && yarn test
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"test": "NODE_OPTIONS=\"--loader ts-node/esm\" c8 mocha --require ts-node/register",
"release": "npm run build && np",
"dry-run": "ts-node src/dry-run/index.ts",
"test-fork": "cd ./test/forks/ && sh ./test-fork.sh"
"test-fork": "cd ./scripts/ && sh ./test-fork.sh"
},
"dependencies": {
"alchemy-sdk": "^3.3.1",
Expand All @@ -61,4 +61,4 @@
"tsup": "^6.1.2",
"typescript": "^5.0.0"
}
}
}
File renamed without changes.
2 changes: 1 addition & 1 deletion test/forks/test-fork.sh → scripts/test-fork.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ git fetch floor
git merge floor/main --no-edit

# copy the .env.example file to .env
cp ../../../../.env .env
cp ../../../.env .env

# Run tests
yarn test
4 changes: 3 additions & 1 deletion src/ingestors/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { FxHashIngestor } from './fxhash';
import { MintIngestor } from '../lib/types/mint-ingestor';
import { ProhibitionDailyIngestor } from './prohibition-daily';
import { FxHashIngestor } from './fxhash';
import { RaribleIngestor } from './rarible';
import { TransientIngestor } from './transient-base';

export type MintIngestionMap = {
[key: string]: MintIngestor;
Expand All @@ -11,6 +12,7 @@ export const ALL_MINT_INGESTORS: MintIngestionMap = {
'prohibition-daily': new ProhibitionDailyIngestor(),
fxhash: new FxHashIngestor(),
rarible: new RaribleIngestor(),
transient: new TransientIngestor(),
};

export * from './';
42 changes: 42 additions & 0 deletions src/ingestors/transient-base/abi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export const TRANSIENT_BASE_ABI = [
{
inputs: [],
name: 'protocolFee',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{ internalType: 'address', name: 'nftAddress', type: 'address' },
{ internalType: 'uint256', name: 'tokenId', type: 'uint256' },
{ internalType: 'address', name: 'recipient', type: 'address' },
{ internalType: 'uint256', name: 'numberToMint', type: 'uint256' },
{ internalType: 'uint256', name: 'presaleNumberCanMint', type: 'uint256' },
{ internalType: 'bytes32[]', name: 'proof', type: 'bytes32[]' },
],
name: 'purchase',
outputs: [{ internalType: 'uint256', name: 'refundAmount', type: 'uint256' }],
stateMutability: 'payable',
type: 'function',
},
];

/**
* This ABI also works for ERC721TL contracts
*/
export const TRANSIENT_ERC7160TL_ABI = [
{
inputs: [
{ internalType: 'address', name: 'nftAddress', type: 'address' },
{ internalType: 'address', name: 'recipient', type: 'address' },
{ internalType: 'uint256', name: 'numberToMint', type: 'uint256' },
{ internalType: 'uint256', name: 'presaleNumberCanMint', type: 'uint256' },
{ internalType: 'bytes32[]', name: 'proof', type: 'bytes32[]' },
],
name: 'purchase',
outputs: [{ internalType: 'uint256', name: 'refundAmount', type: 'uint256' }],
stateMutability: 'payable',
type: 'function',
},
];
122 changes: 122 additions & 0 deletions src/ingestors/transient-base/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { MintContractOptions, MintIngestor, MintIngestorResources } from '../../lib/types/mint-ingestor';
import { MintIngestionErrorName, MintIngestorError } from '../../lib/types/mint-ingestor-error';
import { MintInstructionType, MintTemplate } from '../../lib/types/mint-template';
import { TRANSIENT_BASE_ABI, TRANSIENT_ERC7160TL_ABI } from './abi';
import {
getTransientBaseMintByAddressAndChain,
getTransientBaseMintByURL,
transientSupports,
} from './offchain-metadata';

import { BigNumber } from 'alchemy-sdk';
import { MintTemplateBuilder } from '../../lib/builder/mint-template-builder';
import { getTransientProtocolFeeInEth } from './onchain-metadata';

export class TransientIngestor implements MintIngestor {
configuration = {
supportsContractIsExpensive: true,
};

async supportsUrl(resources: MintIngestorResources, url: string): Promise<boolean> {
if (new URL(url).hostname !== 'www.transient.xyz') {
return false;
}
try {
const { chainId, contractAddress } = await getTransientBaseMintByURL(resources, url);
return !!chainId && !!contractAddress;
} catch (error) {
return false;
}
}

async supportsContract(resources: MintIngestorResources, contract: MintContractOptions): Promise<boolean> {
const { chainId, contractAddress } = contract;
if (!chainId || !contractAddress) {
return false;
}
return await transientSupports(contract, resources);
}

async createMintTemplateForUrl(resources: MintIngestorResources, url: string): Promise<MintTemplate> {
const isCompatible = await this.supportsUrl(resources, url);
if (!isCompatible) {
throw new MintIngestorError(MintIngestionErrorName.IncompatibleUrl, 'Incompatible URL');
}

const { chainId, contractAddress } = await getTransientBaseMintByURL(resources, url);

if (!chainId || !contractAddress) {
throw new MintIngestorError(MintIngestionErrorName.MissingRequiredData, 'Missing required data');
}

return this.createMintForContract(resources, { chainId, contractAddress, url });
}

async createMintForContract(resources: MintIngestorResources, contract: MintContractOptions): Promise<MintTemplate> {
const { chainId, contractAddress } = contract;
if (!chainId || !contractAddress) {
throw new MintIngestorError(MintIngestionErrorName.MissingRequiredData, 'Missing required data');
}

const mintBuilder = new MintTemplateBuilder()
.setMintInstructionType(MintInstructionType.EVM_MINT)
.setPartnerName('Transient');

if (contract.url) {
mintBuilder.setMarketingUrl(contract.url);
}

// asides name and image no other metadata we need is onchain so we can just use the offchain metadata
const {
name,
image,
description,
priceInWei,
mintAddress,
public_sale_start_at,
public_sale_end_at,
token_id,
contract_type,
user,
} = await getTransientBaseMintByAddressAndChain(resources, contract.chainId, contract.contractAddress);

mintBuilder.setName(name).setDescription(description).setFeaturedImageUrl(image);
const protocolFee = await getTransientProtocolFeeInEth(chainId, mintAddress, resources.alchemy);
const totalPrice = BigNumber.from(priceInWei).add(BigNumber.from(protocolFee)).toString();

mintBuilder.setMintOutputContract({
chainId,
address: contractAddress,
});

mintBuilder.setCreator({
name: user.name,
imageUrl: user.image,
websiteUrl: user.website,
});

mintBuilder.setMintInstructions({
chainId,
contractAddress: mintAddress,
contractMethod: 'purchase',
contractParams:
contract_type == 'ERC1155TL'
? `["${contractAddress}", ${token_id}, address, 1, 0, []]`
: `["${contractAddress}", address, 1, 0, []]`,
abi: contract_type == 'ERC1155TL' ? TRANSIENT_BASE_ABI : TRANSIENT_ERC7160TL_ABI,
priceWei: totalPrice,
});

const startDate = public_sale_start_at ? new Date(public_sale_start_at) : new Date();
const endDate = public_sale_end_at ? new Date(public_sale_end_at) : null;

const liveDate = new Date() > startDate ? new Date() : startDate;
mintBuilder
.setAvailableForPurchaseEnd(endDate || new Date('2030-01-01'))
.setAvailableForPurchaseStart(startDate || new Date())
.setLiveDate(liveDate);

const output = mintBuilder.build();
return output;
}
}
Loading

0 comments on commit 322d567

Please sign in to comment.