Important
This repository is archived and no longer maintained. Its contract, BatchTransferFraction, stays deployed on the chains listed under Deployments and still works with hypercerts minted on Hypercerts v1. The repository stays public as the record of the contract's source and addresses.
- Hypercerts has reached v2, and the v1 app has been retired. See hypercerts.org/v1-retired.
- For Hypercerts v2, see hypercerts.org and the documentation.
sequenceDiagram
actor o as Owner
participant h as Hypercert Minter Contract
participant b as BatchTransfer Contract
actor r as Recipients
o ->> h: call splitFraction()
h ->> h: split fraction
o ->> h: call setApprovalForAll()
o ->> b: call batchTransfer()
critical will be reverted if the owner is not the owner of each fractions
b --> h: check if caller is the owner of fraction
b ->> r: safeTransferFrom()
end
/// @dev msg.sender must be the owner of all the fraction IDs being transferred
/// @dev msg.sender must have approved the contract to transfer the fractions
/// @dev The length of recipients and fractionIds must be the same
/// @param data The encoded data containing the recipients and fraction IDs
function batchTransfer(bytes memory data) external {
require(data.length > 0, INVALID_DATA());
TransferData memory transferData = abi.decode(data, (TransferData));
require(transferData.recipients.length == transferData.fractionIds.length, INVALID_LENGTHS());
_batchTransfer(transferData.recipients, transferData.fractionIds);
}
/// @notice Transfers fractions to multiple recipients
/// @dev The length of recipients and fractionIds must be the same
/// @dev The caller must be the owner of all the fraction IDs being transferred
/// @param recipients The addresses of the recipients
/// @param fractionIds The IDs of the fractions to be transferred
function _batchTransfer(address[] memory recipients, uint256[] memory fractionIds) internal {
uint256 length = recipients.length;
for (uint256 i = 0; i < length; i++) {
address recipient = recipients[i];
uint256 fractionId = fractionIds[i];
require(hypercertToken.ownerOf(fractionId) == msg.sender, INVALID_CALLER(msg.sender));
hypercertToken.safeTransferFrom(msg.sender, recipient, fractionId, 1, "");
}
emit BatchFractionTransfer(msg.sender, recipients, fractionIds);
}Important
make sure you own the hypercerts.
most of hypercerts have CREATOR ONLY transfer restriction, so make sure you created the hypercerts as well.
-
Encode data with ethers or viem.
with ethers
import { ethers } from "ethers"; ... const recipients = ["0x123....", "0x456...."]; const fractionIds = [BigInt("23894....5301"), BigInt("23894....5302")]; const encodedData = ethers.AbiCoder.defaultAbiCoder().encode( [`tuple(address[], uint256[])`], [[recipients, fractionIds]] ); console.log('Encoded Data:', encodedData); // e.g. Encoded Data: 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000006aa005386f53ba7b980c61e0d067cabc7602a620000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000c000000000000000000000000000000002
with viem
import { encodeAbiParameters } from 'viem'; ... const recipients = ["0x123....", "0x456...."]; const fractionIds = [BigInt("23894....5301"), BigInt("23894....5302")]; const abiParams = [ { type: 'tuple', components: [{ type: 'address[]' }, { type: 'uint256[]' }], }, ]; const encodedData = encodeAbiParameters(abiParams, [ [recipients, fractionIds], ]);
-
In the HypercertsMinter contract on the chain where you want to execute batch transfer, call setApprovalForAll (0xa22cb465) to approve the batchTransfer contract to send hypercerts.
operator == BatchTransfer contract address, approved == true -
call batchTransfer function
| chain | chainId | address |
|---|---|---|
| Sepolia | 11155111 | 0x59e07f1cc8eb8eca2703179a7217673318a0fe47 |
| Base Sepolia | 84532 | 0x3C0FaAA04078d715BB05Af82Ca99c41623AeC5Ae |
| Arbitrum Sepolia | 421614 | 0x0fCCa2bAd3103934304874E782450688B7a044B0 |
| Optimism | 10 | 0xf77e452ec289da0616574aae371800ca4d6315b1 |
| Base | 8453 | 0xc4aEB039BC432343bf4dB57Be203E0540d385a18 |
| Arbitrum | 42161 | 0x8b973c408c2748588b3ECFfDA06D670819FbEb1D |
| Celo | 42220 | 0xB64B7e4793D72958e028B1D5D556888b115c4c3E |
MIT, as the SPDX-License-Identifier in each source file says.