Skip to content

Commit

Permalink
Replace create collection with raw API call to faciliate api key
Browse files Browse the repository at this point in the history
  • Loading branch information
cynsupercat committed Dec 19, 2023
1 parent 175eff3 commit cd68789
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 18 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ REGISTRATION_ADDRESS=0xDbA6129C02E69405622fAdc3d5A7f8d23eac3b97
GAS_LIMIT=7000000
GAS_PRICE=40000000000

# Your environment's api key generated from https://hub.immutable.com/
API_KEY=sk_imapik-test-vsOfpZHdRGLUQ9KL2E1U_9e61f7

#=============================================
# Bulk Minting
#=============================================
Expand Down
78 changes: 78 additions & 0 deletions src/libs/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { Signer } from '@ethersproject/abstract-signer';
import {
AlchemyProvider,
JsonRpcProvider,
Networkish,
} from '@ethersproject/providers';
import BN from 'bn.js';
import * as encUtils from 'enc-utils';

export function wait(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
Expand Down Expand Up @@ -58,3 +61,78 @@ export function getProvider(
},
);
}

type SignatureOptions = {
r: BN;
s: BN;
recoveryParam: number | null | undefined;
};

// used to sign message with L1 keys. Used for registration
function serializeEthSignature(sig: SignatureOptions): string {
// This is because golang appends a recovery param
// https://github.com/ethers-io/ethers.js/issues/823
return encUtils.addHexPrefix(
encUtils.padLeft(sig.r.toString(16), 64) +
encUtils.padLeft(sig.s.toString(16), 64) +
encUtils.padLeft(sig.recoveryParam?.toString(16) || '', 2),
);
}

function importRecoveryParam(v: string): number | undefined {
const isValidBigNumber =
new BN(v, 16).cmp(new BN(27)) !== -1
? new BN(v, 16).sub(new BN(27)).toNumber()
: new BN(v, 16).toNumber();
return v.trim() ? isValidBigNumber : undefined;
}

// used chained with serializeEthSignature. serializeEthSignature(deserializeSignature(...))
function deserializeSignature(sig: string, size = 64): SignatureOptions {
const removedHexPrefixSig = encUtils.removeHexPrefix(sig);
return {
r: new BN(removedHexPrefixSig.substring(0, size), 'hex'),
s: new BN(removedHexPrefixSig.substring(size, size * 2), 'hex'),
recoveryParam: importRecoveryParam(
removedHexPrefixSig.substring(size * 2, size * 2 + 2),
),
};
}

export async function signRaw(
payload: string,
signer: Signer,
): Promise<string> {
const signature = deserializeSignature(await signer.signMessage(payload));
return serializeEthSignature(signature);
}

type IMXAuthorisationHeaders = {
timestamp: string;
signature: string;
};

export async function generateIMXAuthorisationHeaders(
ethSigner: Signer,
): Promise<IMXAuthorisationHeaders> {
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = await signRaw(timestamp, ethSigner);

return {
timestamp,
signature,
};
}

export async function signMessage(
message: string,
signer: Signer,
): Promise<{ message: string; ethAddress: string; ethSignature: string }> {
const ethAddress = await signer.getAddress();
const ethSignature = await signRaw(message, signer);
return {
message,
ethAddress,
ethSignature,
};
}
54 changes: 36 additions & 18 deletions src/onboarding/3-create-collection.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { keccak256 } from '@ethersproject/keccak256';

Check failure on line 1 in src/onboarding/3-create-collection.ts

View workflow job for this annotation

GitHub Actions / Lint

Cannot find module '@imtbl/sdk' or its corresponding type declarations.
import { toUtf8Bytes } from '@ethersproject/strings';
import { Wallet } from '@ethersproject/wallet';
import { ImLogger, WinstonLogger } from '@imtbl/imlogging';
import { CreateCollectionParams, ImmutableXClient } from '@imtbl/imx-sdk';
import { getProvider, requireEnvironmentVariable } from 'libs/utils';
import { config, immutablexClient } from '@imtbl/sdk';
import axios from 'axios';
import {
generateIMXAuthorisationHeaders,
getEnv,
getProvider,
requireEnvironmentVariable,
} from 'libs/utils';

import env from '../config/client';
import { loggerConfig } from '../config/logging';
Expand All @@ -22,18 +30,16 @@ const component = '[IMX-CREATE-COLLECTION]';
const signer = wallet.connect(provider);
const ownerPublicKey = wallet.publicKey;

const user = await ImmutableXClient.build({
...env.client,
signer,
enableDebug: true,
});

log.info(component, 'Creating collection...', collectionContractAddress);
console.log(getEnv('API_KEY'));

/**
* Edit your values here
*/
const params: CreateCollectionParams = {
const { timestamp, signature } = await generateIMXAuthorisationHeaders(
signer,
);
const createCollectionRequest = {
/**
* Edit your values here
*/
name: 'ENTER_COLLECTION_NAME',
// description: 'ENTER_COLLECTION_DESCRIPTION (OPTIONAL)',
contract_address: collectionContractAddress,
Expand All @@ -44,15 +50,27 @@ const component = '[IMX-CREATE-COLLECTION]';
project_id: parseInt(projectId, 10),
};

let collection;
try {
collection = await user.createCollection(params);
} catch (error) {
throw new Error(JSON.stringify(error, null, 2));
const headers: Record<string, string> = {
'Content-type': 'application/json',
'IMX-Signature': signature,
'IMX-Timestamp': timestamp,
};

const apiKey = getEnv('API_KEY');
if (apiKey) {
headers['x-immutable-api-key'] = apiKey;
}

const resp = await axios.post(
`${getEnv('PUBLIC_API_URL')}/collections`,
createCollectionRequest,
{
headers,
},
);

log.info(component, 'Created collection');
console.log(JSON.stringify(collection, null, 2));
console.log(JSON.stringify(resp.data, null, 2));
})().catch(e => {
log.error(component, e);
process.exit(1);
Expand Down

0 comments on commit cd68789

Please sign in to comment.