Authorizing Access List Purchases
The contracts use a process of approving an access list purchase called ECR Recovery. Put simply, the contract allows wallets that are access listed to buy tokens only if the authorising wallet has pre-approved the address. This allows you to implement your own access listing logic.
When configuring a contract, you will be asked to provide an Access List Authorising Address
. This should only be used to approve access list purchases and should not receive any funds.
The following code can be used on your server to authorise a wallet for an access list purchase:
// Ethers documentation: https://docs.ethers.io/v5/getting-started/
import { ethers } from 'ethers';
import dayjs from 'dayjs';
// address: The wallet address of the customer to approve
async function approveAuthorised(
address: string, // User address
amount: number, // Amount of tokens user wants to buy
): Promise<{
amount: number;
totalPrice: number;
expires: number;
signature: string;
}> {
const privateKey = '<<access listA authorising address private key>>';
const contractAddress = '<<contract address from UI or API>>';
// Initialise a wallet using the private key
const wallet = new ethers.Wallet(privateKey);
// Convert price in eth into gwei
const price = ethers.utils.parseEther(ethPrice.toString());
// The contract accepts the total price, not a price per token
const totalPrice = price.mul(amount).toNumber();
// Expiry timestamp (must be in unix time) of the signature being generated
const expires = dayjs().add(15, 'minute').unix();
// Hash together the following:
// Contract address, user's address, token amount, token price, expiry
const solidityHash = ethers.utils.solidityKeccak256(
['address', 'address', 'uint256', 'uint256', 'uint256'],
[contractAddress, address, amount, totalPrice, expires]
);
// Generate the signature
const signature = await wallet.signMessage(
ethers.utils.arrayify(solidityHash)
);
return {
amount,
totalPrice,
expires,
signature
};
}
The amount
, totalPrice
, expires
, signature values
returned can be safely sent to the client to be used in the Client SDK buyAuthorised
function or by calling the contract directly by another means.
Securing Private Keys
HyperMint uses 2 separate wallets:
- Customer Wallet: Receives funds from primary sales
- Access List Authorising Wallet: Approves access list purchases
To access the wallet, a private key is used which depending on the wallet, allows the user access to transfer funds, approve an access list purchase and any other possible action on a wallet.
It is essential that you keep your private key safe. Do not commit it in code to a repository
The access listing process requires access to a wallet to sign a message which in turn requires a private key or similar mechanism. There are various ways to keep this key safe going from the most basic to more secure:
- Use environment variables on the server
- Use a secrets manager such as AWS Secret Manager
- Use a key management solution such as AWS KMS
The first two options can use the above code to initialise a wallet with the key while the last option requires a different approach.
AWS KMS
Although AWS is called out here, other key management solutions exist. HyperMint does not endorse or recommend any individual solution
If you are using AWS for your hosting, it may make sense to also use Key Management Service (KMS) to manage the private keys of your wallet. https://aws.amazon.com/kms/
At a high level, the private key can never be extracted from the service and therefore cannot be shared or lost, protecting the wallet. Instead, you send transactions and messages to be signed to the service and get back a signature to use.
Many guides exist on Google including this one: https://luhenning.medium.com/the-dark-side-of-the-elliptic-curve-signing-ethereum-transactions-with-aws-kms-in-javascript-83610d9a6f81
A NPM module also exists to simplify the process: https://www.npmjs.com/package/ethers-aws-kms-signer
Always review third party code and modules before using in your own systems
Feedback
Something not quite right, unclear or can't find what you are looking for? Please let us know at [email protected] and we will get back to you as soon as we can.
Updated about 1 year ago