Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into manifold
Browse files Browse the repository at this point in the history
  • Loading branch information
chainparser committed Jul 22, 2024
2 parents f7c1d3e + 9c567cf commit ee57348
Show file tree
Hide file tree
Showing 13 changed files with 261 additions and 13 deletions.
1 change: 1 addition & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
ALCHEMY_API_KEY=
SIMULATE_DURING_TESTS=true
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@
"format": "eslint src/**/*.ts --fix",
"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"
"dry-run": "ts-node src/dry-run/index.ts",
"test-fork": "cd ./test/forks/ && sh ./test-fork.sh"
},
"dependencies": {
"alchemy-sdk": "^3.3.1",
"axios": "^1.7.2",
"dotenv": "^16.4.5",
"ethers": "^6.13.1",
"np": "^10.0.6",
"ts-node": "10.9.1",
"tslib": "^2.6.3"
Expand Down
12 changes: 12 additions & 0 deletions src/dry-run/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { simulateEVMTransactionWithAlchemy } from "../lib/simulation/simulation";
import { ALL_MINT_INGESTORS } from "../ingestors";
import { mintIngestorResources } from "../lib/resources";
import dotenv from 'dotenv';
import { EVMMintInstructions } from "src/lib";
dotenv.config();

const args = process.argv.slice(2);
Expand Down Expand Up @@ -49,6 +51,16 @@ const resources = mintIngestorResources();
process.exit(1);
}
console.log(JSON.stringify(result, null, 2));

console.log('Simulating transaction....');
const mintInstructions = result.mintInstructions as EVMMintInstructions;
const simulationResult = await simulateEVMTransactionWithAlchemy(mintInstructions);
if (simulationResult.success) {
console.log('✅ Simulation Success');
} else {
console.log('❌ Simulation Failed');
console.log(JSON.stringify(simulationResult, null, 2));
}
} catch (error) {
console.error(error);
process.exit(1);
Expand Down
6 changes: 3 additions & 3 deletions src/ingestors/fxhash/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class FxHashIngestor implements MintIngestor {
throw new MintIngestorError(MintIngestionErrorName.CouldNotResolveMint, 'Project not found');
}

const { priceWei, type } = fxHashGetPricingFromParams(token);
const { priceWei, type, reserveId } = fxHashGetPricingFromParams(token);

if (!type) {
throw new MintIngestorError(MintIngestionErrorName.CouldNotResolveMint, 'Could not resolve mint type');
Expand All @@ -58,13 +58,13 @@ export class FxHashIngestor implements MintIngestor {
websiteUrl: token.author.account.profile.website,
description: token.author.account.profile.description,
twitterUsername: token.author.account.profile.twitter?.split('/').pop(),
})
});

mintBuilder.setMintInstructions({
chainId: contract.chainId,
contractAddress,
contractMethod: 'buy',
contractParams: `["${contract.contractAddress}", 0, 1, address]`,
contractParams: `["${contract.contractAddress}", ${reserveId}, 1, address]`,
abi: abi,
priceWei: `${priceWei}`,
});
Expand Down
10 changes: 9 additions & 1 deletion src/ingestors/fxhash/offchain-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ export function fxHashGetPricingFromParams(
const { pricingFixed, pricingDutchAuction, isFrame } = generativeToken;
let price = 0;
let type: FxHashPricingType | undefined = isFrame ? FxHashPricingType.FRAME : undefined;
let reserveId: number = 1;

if (!!generativeToken.openEditionsEndsAt) {
reserveId = 0;
}
if (pricingFixed) {
type = type || FxHashPricingType.FIXED;
price = pricingFixed.price;
Expand All @@ -166,7 +171,10 @@ export function fxHashGetPricingFromParams(
price = pricingDutchAuction.restingPrice;
}

return { priceWei: price, type: type }
if (type === FxHashPricingType.DUTCH_AUCTION) {
}

return { priceWei: price, type: type, reserveId: reserveId }
}

const BASE_FRAME_CONTRACT_ADDRESS = '0x6e625892C739bFD960671Db5544E260757480725';
Expand Down
3 changes: 1 addition & 2 deletions src/ingestors/prohibition-daily/abi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export const PROHIBITION_DAILY_ABI = [
stateMutability: 'view',
type: 'function',
},

{
inputs: [],
name: 'saleStart',
Expand Down Expand Up @@ -88,5 +87,5 @@ export const PROHIBITION_DAILY_ABI = [
outputs: [],
stateMutability: 'payable',
type: 'function',
},
}
];
73 changes: 73 additions & 0 deletions src/lib/simulation/simulation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Alchemy, BigNumber, Network, Utils } from "alchemy-sdk";
import { EVMMintInstructions } from "../types";
export const SIGNER1_WALLET = '0x965EF172b303B0BcdC38669DF1De3c26BAD2dB8a';
export const TEST_RECIPIENT = '0x0cc9601298361e844451a7e35e1d7fcd72750e47';

export const NETWORKS: Record<number, Network> = {
1: Network.ETH_MAINNET,
5: Network.ETH_GOERLI,
137: Network.MATIC_MAINNET,
42161: Network.ARB_MAINNET,
80001: Network.MATIC_MUMBAI,
8453: Network.BASE_MAINNET,
84531: Network.BASE_GOERLI,
11155111: Network.ETH_SEPOLIA
};

export const simulateEVMTransactionWithAlchemy = async (mintInstructions: EVMMintInstructions, blockNumber?: string): Promise<{ message: string, success: boolean, rawSimulationResult: any }> => {
const alchemy = new Alchemy({
apiKey: process.env.ALCHEMY_API_KEY,
network: NETWORKS[mintInstructions.chainId],
});

const abi = mintInstructions.abi;
const iface = new Utils.Interface(abi);

const paramsArray = prepareContractParams(mintInstructions.contractParams);

const data = iface.encodeFunctionData(mintInstructions.contractMethod, paramsArray);

const tx = {
to: mintInstructions.contractAddress,
from: SIGNER1_WALLET,
data: data,
value: BigNumber.from(mintInstructions.priceWei || '0').toHexString().replace('0x0', '0x'),
};

const simResult = await alchemy.transact.simulateExecution(tx, blockNumber ? blockNumber : undefined);

const failedCalls: any = simResult.calls.find((call) => call.error) || [];

const message = failedCalls?.revertReason;
const success = failedCalls.length === 0;

if (!success) {
console.log(`Error Simulating: ${message}, ${JSON.stringify(simResult)}`);
}

return { message, success, rawSimulationResult: simResult };
}

export const prepareContractParams = (template: string): any[] => {
const regex = /{{(\w+)}}|tokenId|address|encodedAddress/g;

const replacedTemplate = template.replace(regex, (match) => {
switch (match) {
case 'address':
return `"${TEST_RECIPIENT}"`;
case 'encodedAddress':
return `"${encodeAddress(TEST_RECIPIENT)}"`;
default:
return '""';
}
});

return JSON.parse(replacedTemplate);
};

export const encodeAddress = (address: string) => {
const rawAddress = address.replace('0x', '');

return '0x' + rawAddress.padStart(64, '0');
};

1 change: 1 addition & 0 deletions test/forks/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
clones/
58 changes: 58 additions & 0 deletions test/forks/test-fork.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/bin/bash

if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
echo "Usage: $0 <git-url> [branch-name]"
exit 1
fi

# if the URL is of the format https://github.com/pbkompasz/mobile-minting/tree/ingestor-highlight then pull both the branch name and the repo name
if [[ $1 == *"tree"* ]]; then
BRANCH_NAME=$(echo $1 | cut -d'/' -f7)
REPO_NAME=$(echo $1 | cut -d'/' -f5)

# remove the tree part from the URL
GIT_URL=$(echo $1 | cut -d'/' -f1-5)
GIT_URL="$GIT_URL"
else
GIT_URL=$1
BRANCH_NAME=${2:-main}
fi

echo "GIT_URL: $GIT_URL"
echo "BRANCH_NAME: $BRANCH_NAME"

ORG_NAME=$(basename $(dirname $GIT_URL) .git)

echo "ORG_NAME: $ORG_NAME"

cd clones

# if the folder name exists, delete it
if [ -d $ORG_NAME ]; then
rm -rf $ORG_NAME
fi

# Clone the fork into a directory with the name of the organization the fork is in
git clone $GIT_URL $ORG_NAME
cd $ORG_NAME

# Move to the specified branch
git checkout $BRANCH_NAME

# Install dependencies
yarn install

# Add the floornfts/mobile-minting repo as a remote "floor"
git remote add floor https://github.com/floornfts/mobile-minting.git

# Fetch the remote "floor"
git fetch floor

# Merge main from "floor" into the current branch
git merge floor/main --no-edit

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

# Run tests
yarn test
34 changes: 31 additions & 3 deletions test/ingestors/fxhash.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,36 @@ import { FxHashIngestor } from '../../src/ingestors/fxhash';
import { mintIngestorResources } from '../../src/lib/resources';
import { EVMMintInstructions } from '../../src/lib/types/mint-template';
import { MintTemplateBuilder } from '../../src/lib/builder/mint-template-builder';
import { basicIngestorTests } from '../shared/basic-ingestor-tests';

describe('fxhash', function () {

basicIngestorTests(
new FxHashIngestor(),
mintIngestorResources(),
{
successUrls: [
'https://fxhash.xyz/generative/slug/allegro',
'https://fxhash.xyz/generative/slug/graphomania',
'https://www.fxhash.xyz/generative/slug/the-space-in-between'
],
failureUrls: ['https://example.com'],
successContracts: [{
chainId: 8453,
contractAddress: '0x914cf2d92b087C9C01a062111392163c3B35B60e'
}],
failureContracts: [
{
chainId: 8453,
contractAddress: '0x6140F00e4Ff3936702E68744f2b5978885464cbB'
}
]
},
{
// 8453: '0x107A60C'
}
);

it('supportsUrl: Returns false for an unsupported URL', async function () {
const ingestor = new FxHashIngestor();
const url = 'https://example.com';
Expand Down Expand Up @@ -39,7 +67,7 @@ describe('fxhash', function () {

expect(mintInstructions.contractAddress).to.equal('0x6e625892C739bFD960671Db5544E260757480725');
expect(mintInstructions.contractMethod).to.equal('buy');
expect(mintInstructions.contractParams).to.equal('["0x914cf2d92b087C9C01a062111392163c3B35B60e", 0, 1, address]');
expect(mintInstructions.contractParams).to.equal('["0x914cf2d92b087C9C01a062111392163c3B35B60e", 1, 1, address]');
expect(mintInstructions.priceWei).to.equal('4200000000000000');

expect(template.featuredImageUrl).to.equal('ipfs://Qmc9eKhAkQvt1mXq1pD5FP9ZnprBNuU2USq5rELKVdb9uf');
Expand All @@ -65,7 +93,7 @@ describe('fxhash', function () {

expect(mintInstructions.contractAddress).to.equal('0x4bDcaC532143d8d35ed759189EE22E3704580b9D');
expect(mintInstructions.contractMethod).to.equal('buy');
expect(mintInstructions.contractParams).to.equal('["0x755625dEfD0f1Bb90850d533f30176aa7a425f6E", 0, 1, address]');
expect(mintInstructions.contractParams).to.equal('["0x755625dEfD0f1Bb90850d533f30176aa7a425f6E", 1, 1, address]');
expect(mintInstructions.priceWei).to.equal('500000000000000');

expect(template.featuredImageUrl).to.equal('ipfs://QmYV4LXoz18youcW7zREFFFVpPf6Tn1j4QRzmTi1cSPinb');
Expand Down Expand Up @@ -152,7 +180,7 @@ describe('fxhash', function () {

expect(mintInstructions.contractAddress).to.equal('0x6e625892C739bFD960671Db5544E260757480725');
expect(mintInstructions.contractMethod).to.equal('buy');
expect(mintInstructions.contractParams).to.equal('["0x914cf2d92b087C9C01a062111392163c3B35B60e", 0, 1, address]');
expect(mintInstructions.contractParams).to.equal('["0x914cf2d92b087C9C01a062111392163c3B35B60e", 1, 1, address]');
expect(mintInstructions.priceWei).to.equal('4200000000000000');

expect(template.featuredImageUrl).to.equal('ipfs://Qmc9eKhAkQvt1mXq1pD5FP9ZnprBNuU2USq5rELKVdb9uf');
Expand Down
2 changes: 2 additions & 0 deletions test/ingestors/prohibition-daily.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ describe('prohibition-daily', function () {
{ chainId: 8453, contractAddress: '0x965ef172b303b0bcdc38669df1de3c26bad2db8a' },
{ chainId: 8453, contractAddress: 'derp' }
]
}, {
8453: '0xF469C6'
});
it('createMintTemplateForUrl: Returns a mint template for a supported URL', async function () {
const ingestor = new ProhibitionDailyIngestor();
Expand Down
20 changes: 17 additions & 3 deletions test/shared/basic-ingestor-tests.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { expect } from "chai";
import { MintContractOptions, MintIngestor, MintIngestorResources } from "../../src/lib/types/mint-ingestor";
import { MintTemplateBuilder } from "../../src/lib/builder/mint-template-builder";
import { simulateEVMTransactionWithAlchemy } from "../../src/lib/simulation/simulation";
import { EVMMintInstructions } from "../../src/lib/types";

export const basicIngestorTests = (
ingestor: MintIngestor,
Expand All @@ -9,9 +11,12 @@ export const basicIngestorTests = (
successUrls: string[],
failureUrls: string[],
successContracts: MintContractOptions[],
failureContracts: MintContractOptions[]
}
failureContracts: MintContractOptions[],
},
simulationBlocks: { [key: number]: string } = {}
) => {
const shouldSimulate = process.env.SIMULATE_DURING_TESTS === "true";

describe(`${ingestor.constructor.name}-auto`, function () {
const { successUrls, failureUrls, successContracts, failureContracts } = cases;

Expand Down Expand Up @@ -46,6 +51,15 @@ export const basicIngestorTests = (
// Verify that the mint template passed validation
const builder = new MintTemplateBuilder(template);
builder.validateMintTemplate();

if (shouldSimulate) {
const mintInstructions = template.mintInstructions as EVMMintInstructions;
const result = await simulateEVMTransactionWithAlchemy(mintInstructions, simulationBlocks[mintInstructions.chainId]);
expect(result.success).to.be.true;
if (result.success) {
console.log(`✅ Simulation success`);
}
}
}
});
it('createMintForContract: Returns a mint template for a supported contract', async function () {
Expand All @@ -58,4 +72,4 @@ export const basicIngestorTests = (
}
});
});
}
}
Loading

0 comments on commit ee57348

Please sign in to comment.