Skip to content

Commit

Permalink
Merge branch 'main' into multi-chain-alchemy-and-manifold
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismaddern authored Oct 7, 2024
2 parents d7c0d11 + 93fb19c commit 680be9f
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 248 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## What is Mobile Minting?
Mobile Minting unlocks mobile payments for onchain purchases and powers minting in the Floor app.
Mobile Minting unlocks mobile payments for onchain purchases and powers minting in the Rally app (formerly known as Floor!).

**📱 Users pay in-app with In-App Purchases**

Expand All @@ -16,9 +16,9 @@ _Example Mobile Minting user experience._
## What is this repository?
This repository is a **public, contributable collection of Ingestors** that teach Mobile Minting how to support mints from new platforms.

Historically, only Floor could choose what mints users could mint through Floor based on our roadmap, or partnerships, now anyone can build support for any minting platform / product and (provided it meets some safety & reliability checks) it can be included in Mobile Minting.
Historically, only Rally could choose what mints users could mint through Rally based on our roadmap, or partnerships, now anyone can build support for any minting platform / product and (provided it meets some safety & reliability checks) it can be included in Mobile Minting.

This library is included in Floor's platform and executed in a sandboxed environment for indexing mints.
This library is included in Rally's platform and executed in a sandboxed environment for indexing mints.

<br />

Expand Down Expand Up @@ -68,13 +68,13 @@ Today, Mobile Minting supports the following creator platforms:
Base
</td>
<td>
💥 Failing
</td>
<td>
💥 Failing
</td>
<td>
💥 Failing
</td>
</tr>
<tr>
Expand Down Expand Up @@ -218,7 +218,7 @@ A MintTemplate is a standard format for expressing the details of a mint. It's u

_Mapping of MintTemplate fields to an in-app mint._

Once you generate a MintTemplate, Floor will do all the additional work to get the mint live:
Once you generate a MintTemplate, Rally will do all the additional work to get the mint live:

* Map priceWei to an in-app purchase
* Simulate the transaction in multiple scenarios to ensure success
Expand Down Expand Up @@ -281,7 +281,7 @@ In this example we make a template, relying on `getMintMetadataFromSomewhere()`
});
```

_Note: You will typically want to implement either
_Note: You will typically want to implement either `createMintForContract` or `createMintTemplateForUrl`, and then call that one from the other._

You can then build the MintTemplate from the builder.

Expand Down Expand Up @@ -350,7 +350,7 @@ yarn dry-run some-erc-1155-ingestor contract 8453:contractAddress:tokenId
```

# Submitting a Mobile Minting Ingestor
Once you've written a Mobile Minting Ingestor, it needs to be Pull Requested to this repository to be included in the production Floor Mobile Minting ingestion fleet.
Once you've written a Mobile Minting Ingestor, it needs to be Pull Requested to this repository to be included in the production Rally Mobile Minting ingestion fleet.

### Before you submit
- [ ] Ensure your generated MintTemplate works 😄
Expand All @@ -370,7 +370,7 @@ We're excited to see new platforms supported, so will quickly jump to help!
### Hopes and dreams
Mobile Minting started out entirely internal & this is our first experiment in decentralizing it & making it more accessible.

In time, we hope to continue down this path, but for now all ingestors will be reviewed by the Floor engineering team & accepted on the basis of safety, cost & other considerations by Floor.
In time, we hope to continue down this path, but for now all ingestors will be reviewed by the Rally engineering team & accepted on the basis of safety, cost & other considerations by Rally.

We hope to see people (other companies!?) emerge for whom Mobile Minting, and a unified standard for expressing onchain mints is useful, and look forward to working with them to continue this mission.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@floornfts/mobile-minting",
"version": "1.2.0",
"version": "1.2.3",
"repository": "git://github.com/floornfts/mobile-minting.git",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
Expand Down
55 changes: 30 additions & 25 deletions src/ingestors/highlight/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,34 @@ const CONTRACT_ADDRESS = '0x8087039152c472Fa74F47398628fF002994056EA';

export class HighlightIngestor implements MintIngestor {
async supportsUrl(resources: MintIngestorResources, url: string): Promise<boolean> {
const id = url.split('/').pop();
if (!id) {
return false;
}

const collection = await getHighlightCollectionById(resources, id);

if (!collection || collection.chainId !== 8453) {
return false;
}

const urlPattern = /^https:\/\/highlight\.xyz\/mint\/[a-f0-9]{24}$/;
return (
new URL(url).hostname === 'www.highlight.xyz' || new URL(url).hostname === 'highlight.xyz' || urlPattern.test(url)
);
return false;
// const id = url.split('/').pop();
// if (!id) {
// return false;
// }

// const collection = await getHighlightCollectionById(resources, id);

// if (!collection || collection.chainId !== 8453) {
// return false;
// }

// const urlPattern = /^https:\/\/highlight\.xyz\/mint\/[a-f0-9]{24}$/;
// return (
// new URL(url).hostname === 'www.highlight.xyz' || new URL(url).hostname === 'highlight.xyz' || urlPattern.test(url)
// );
}

async supportsContract(resources: MintIngestorResources, contractOptions: MintContractOptions): Promise<boolean> {
if (contractOptions.chainId !== 8453) {
return false;
}
const collection = await getHighlightCollectionByAddress(resources, contractOptions);
if (!collection) {
return false;
}
return true;
return false;
// if (contractOptions.chainId !== 8453) {
// return false;
// }
// const collection = await getHighlightCollectionByAddress(resources, contractOptions);
// if (!collection) {
// return false;
// }
// return true;
}

async createMintForContract(
Expand Down Expand Up @@ -80,7 +82,7 @@ export class HighlightIngestor implements MintIngestor {
throw new MintIngestorError(MintIngestionErrorName.MissingRequiredData, 'Error finding creator');
}

const collectionId = collection.highlightCollection?.id;
const collectionId = collection.highlightCollection?.id || collection.id;

if (!collectionId) {
throw new MintIngestorError(MintIngestionErrorName.MissingRequiredData, 'Collection id not available');
Expand All @@ -93,6 +95,8 @@ export class HighlightIngestor implements MintIngestor {
imageUrl: creator?.creatorAccountSettings?.displayAvatar,
});

mintBuilder.setMintOutputContract({ chainId: 8453, address: collection.highlightCollection.address });

const vectorId = await getHighlightVectorId(resources, collectionId);

if (!vectorId) {
Expand All @@ -109,9 +113,10 @@ export class HighlightIngestor implements MintIngestor {
chainId: 8453,
contractAddress: CONTRACT_ADDRESS,
contractMethod: 'vectorMint721',
contractParams: `[${vectorId}, 1, address]`,
contractParams: `[${vectorId}, quantity, address]`,
abi: MINT_CONTRACT_ABI,
priceWei: totalPriceWei,
supportsQuantity: true,
});

const metadata = await getHighlightMetadata(+vectorId, resources.alchemy);
Expand Down
1 change: 0 additions & 1 deletion src/ingestors/highlight/offchain-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export const getHighlightCollectionById = async (
marketplaceId
accountId
address
symbol
chainId
status
baseUri
Expand Down
13 changes: 7 additions & 6 deletions src/ingestors/highlight/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type Collection = {
symbol: string;
chainId: number;
status: string;
baseUri: string,
baseUri: string;
};

export type CollectionByAddress1 = {
Expand All @@ -23,8 +23,8 @@ export type CollectionByAddress1 = {
symbol: string;
description: string;
sampleImages: string[];
creator: string;
}
creator: string;
};

export type CollectionByAddress2 = {
chainId: number;
Expand All @@ -36,7 +36,8 @@ export type CollectionByAddress2 = {
owner: string;
imageUrl: string;
animationUrl: string;
}
}
address: string;
};
};

export type CollectionByAddress = CollectionByAddress1 & CollectionByAddress2
export type CollectionByAddress = CollectionByAddress1 & CollectionByAddress2;
6 changes: 3 additions & 3 deletions src/ingestors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ export type MintIngestionMap = {
};

export const ALL_MINT_INGESTORS: MintIngestionMap = {
'zora-internal': new ZoraInternalIngestor(),
rodeo: new RodeoIngestor(),
'prohibition-daily': new ProhibitionDailyIngestor(),
fxhash: new FxHashIngestor(),
manifold: new ManifoldIngestor(),
rarible: new RaribleIngestor(),
transient: new TransientIngestor(),
highlight: new HighlightIngestor(),
foundation: new FoundationIngestor(),
'coinbase-wallet': new CoinbaseWalletIngestor(),
'zora-internal': new ZoraInternalIngestor(),
rodeo: new RodeoIngestor(),
'coinbase-wallet': new CoinbaseWalletIngestor()
};

export * from './';
5 changes: 4 additions & 1 deletion src/ingestors/rodeo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,13 @@ export class RodeoIngestor implements MintIngestor {
mintBuilder.setName(name).setDescription(description).setFeaturedImageUrl(image);
const totalPrice = await getRodeoFeeInEth(sale_terms_id, user.address, mintAddress, resources.alchemy);

const tokenIdNum = parseInt(tokenId);
mintBuilder.setMintOutputContract({
chainId,
address: contractAddress,
tokenId: isNaN(tokenIdNum) ? null : tokenIdNum,
});

mintBuilder.setCreator({
name: user.name,
imageUrl: user.image,
Expand All @@ -93,6 +95,7 @@ export class RodeoIngestor implements MintIngestor {
priceWei: totalPrice,
mintFeePerTokenWei: totalPrice,
supportsQuantity: true,
tokenId: tokenIdNum
});

const startDate = public_sale_start_at ? new Date(public_sale_start_at) : new Date();
Expand Down
4 changes: 2 additions & 2 deletions src/ingestors/zora-internal/zora-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,13 @@ export class ZoraMetadataProvider {
const mintFeePerTokenWei = mintPriceWei;
if (mintType === 'ZORA_TIMED') {
//mint(address mintTo, uint256 quantity, address collection, uint256 tokenId, address mintReferral, string comment)
params = `[address, quantity, "${tokenDetails.collection.address}", tokenId, "${FLOOR_REFERRER_REWARDS_ADDRESS}", "Minted on floor.fun"]`;
params = `[address, quantity, "${tokenDetails.collection.address}", tokenId, "${FLOOR_REFERRER_REWARDS_ADDRESS}", "Minted on rally.xyz"]`;
contractAddress = ZORA_TIMED_MINT_STRATEGY_ADDRESS;
method = 'mint';
abi = ZORA_TIMED_MINT_ABI;
supportsQuantity = true;
if (parseInt(mintPriceWei) <= 111000000000000) {
defaultQuantity = 11;
defaultQuantity = 1;
mintPriceWei = (BigInt(mintPriceWei) * BigInt(defaultQuantity)).toString();
}
} else if (mintType === 'FIXED_PRICE') {
Expand Down
4 changes: 3 additions & 1 deletion test/ingestors/foundation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ describe('foundation', function () {
expect(mintInstructions.contractParams).to.equal(
'["0x89E63F58da71E9CD4DA439C3D1194917c67eb869", 1, address, "0x0000000000000000000000000000000000000000"]',
);
expect(mintInstructions.priceWei).to.equal('7700000000000000');

// This has now ended and the API returns 0 for the price
expect(mintInstructions.priceWei).to.equal('0');

expect(template.featuredImageUrl).to.equal(
'https://f8n-production-collection-assets.imgix.net/8453/0x89E63F58da71E9CD4DA439C3D1194917c67eb869/pre_reveal/nft.jpg',
Expand Down
64 changes: 35 additions & 29 deletions test/ingestors/highlight.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,29 @@ import { basicIngestorTests } from '../shared/basic-ingestor-tests';

const resources = mintIngestorResources();

describe('highlight', function () {
basicIngestorTests(new HighlightIngestor(), resources, {
successUrls: [
'https://highlight.xyz/mint/665fa33f07b3436991e55632',
'https://highlight.xyz/mint/66856628ff8a01fdccc132f4',
],
failureUrls: [
'https://highlight.xyz/mint/66963c500b48236f1acf322b',
'https://foundation.app/mint/base/the-billows',
],
successContracts: [
{ chainId: 8453, contractAddress: '0x0E5DDe3De7cf2761d8a81Ee68F48410425e2dBbA' },
{ chainId: 8453, contractAddress: '0xBE96B2572CA0F1ac8ec6323Bc9037AffD270bA7F' },
],
failureContracts: [{ chainId: 5000, contractAddress: '0x62F8C536De24ED32611f128f64F6eAbd9b82176c' }],
});
describe.skip('highlight', function () {
basicIngestorTests(
new HighlightIngestor(),
resources,
{
successUrls: [
'https://highlight.xyz/mint/66856628ff8a01fdccc132f4',
'https://highlight.xyz/mint/66d03b0eaae45d4534822482',
],
failureUrls: [
'https://highlight.xyz/mint/66963c500b48236f1acf322b',
'https://foundation.app/mint/base/the-billows',
],
successContracts: [
{ chainId: 8453, contractAddress: '0x0E5DDe3De7cf2761d8a81Ee68F48410425e2dBbA' },
{ chainId: 8453, contractAddress: '0x7022a51D648CEB4f4D290a81A0E543979a003e86' },
],
failureContracts: [{ chainId: 5000, contractAddress: '0x62F8C536De24ED32611f128f64F6eAbd9b82176c' }],
},
{
'8453': '0x124F956',
},
);
it('supportsUrl: Returns false for an unsupported URL', async function () {
const ingestor = new HighlightIngestor();
const url = 'https://example.com';
Expand All @@ -45,40 +52,39 @@ describe('highlight', function () {

it('createMintTemplateForUrl: Returns a mint template for a supported URL', async function () {
const ingestor = new HighlightIngestor();
const url = 'https://highlight.xyz/mint/665fa33f07b3436991e55632';
const url = 'https://highlight.xyz/mint/66856628ff8a01fdccc132f4';
const resources = mintIngestorResources();
const template = await ingestor.createMintTemplateForUrl(resources, url);

// Verify that the mint template passed validation
const builder = new MintTemplateBuilder(template);
builder.validateMintTemplate();

expect(template.name).to.equal('COMBAT MODE by Emily Xie');
expect(template.description).to.contain(
'It depicts two creatures in battle, melding the nostalgia of old school video games with the contemporary possibilities of digital illustration.',
);
expect(template.name).to.equal('Based Fren$');
expect(template.description).to.contain('3,333 Based Fren$ muy basados');
const mintInstructions = template.mintInstructions as EVMMintInstructions;

expect(mintInstructions.contractAddress).to.equal('0x8087039152c472Fa74F47398628fF002994056EA');
expect(template.mintOutputContract?.address).to.equal('0x0E5DDe3De7cf2761d8a81Ee68F48410425e2dBbA');
expect(mintInstructions.contractMethod).to.equal('vectorMint721');
expect(mintInstructions.contractParams).to.equal('[866, 1, address]');
expect(mintInstructions.priceWei).to.equal('2100000000000000');
expect(mintInstructions.contractParams).to.equal('[1176, quantity, address]');
expect(mintInstructions.priceWei).to.equal('800000000000000');

expect(template.featuredImageUrl).to.equal(
'https://img.reservoir.tools/images/v2/base/z9JRSpLYGu7%2BCZoKWtAuANCXTgWBry4OTpgBkNYv7UVX%2FOELQ1B1IQGOoFgJBPmEzWQJa5hKPeiypcjXnSgXVEhZJDeOg9vk5slunBxp8ABMKIlkw3COL8nejLu9cx7f5QrJHJecqNaXIZCHlWY311DY%2F4e9zjeJnyY%2Fvp3J%2FivCSdJShfdu2%2FoCfqed8TvVTrlrElK7Wp8owCwKnZNhaw%3D%3D',
'https://img.reservoir.tools/images/v2/base/z9JRSpLYGu7%2BCZoKWtAuAI37ZMpGmBWtUpAQDl1tI6DEJRvIrkDVCqzOxkdek%2BfesLtA3sYS0SXZeU4voi8R9rQD1uumcaPxveg8%2B3UfVgFBR82zeA%2FzrfIHHRUbhHMTK4V08qvpcJ5dRYdYVwRvZPTKTulv78c%2FB6vgLUkdfSX0ND53Mjp2wUysnfKmYO5rOIxPwl1ACpM%2BOQDWOOSOzg%3D%3D',
);

if (template.creator) {
expect(template.creator.name).to.equal('Emily Xie');
expect(template.creator.walletAddress).to.equal('0x591a0b1994e8880215b89c5b9cd8d0738e5c0f1e');
expect(template.creator.name).to.equal('Nxsh');
expect(template.creator.walletAddress).to.equal('0xf5977a695e85d3046ed8ce03dd3b562e40532200');
expect(template.creator.imageUrl).to.equal(
'https://highlight-creator-assets.highlight.xyz/main/image/91eaf712-b9de-49e4-8674-85f37dd823e0.png',
'https://highlight-creator-assets.highlight.xyz/main/image/e5eca4b9-1b8e-4ebf-8cd5-e0f6d618e15a.png',
);
}

expect(template.marketingUrl).to.equal(url);
expect(template.availableForPurchaseStart?.getTime()).to.equal(+new Date('2024-06-05T16:00:00.000Z'));
expect(template.availableForPurchaseEnd?.getTime()).to.equal(+new Date('2024-08-31T16:00:00.000Z'));
expect(template.availableForPurchaseStart?.getTime()).to.equal(+new Date(1720042380000));
expect(template.availableForPurchaseEnd?.getTime()).to.equal(+new Date(1893456000000));
});

it.skip('createMintTemplateForUrl: Returns a mint template for a supported URL with free price', async function () {
Expand Down
Loading

0 comments on commit 680be9f

Please sign in to comment.