Skip to main content

Overview

Since GatePass tickets are ERC721 NFTs, they can be transferred between wallet addresses just like any other NFT. This guide explains the transfer process, restrictions, and security considerations.
Ticket transfers may be restricted by event organizers. Always check transfer policies before purchasing.

When to Transfer Tickets

Common scenarios for ticket transfers:
  • Gift to a Friend - Send tickets you purchased to someone else
  • Resale - Sell tickets on secondary marketplaces (if allowed)
  • Name Change - Transfer to your other wallet address
  • Can’t Attend - Pass tickets to someone who can use them

Transfer Methods

Transfer tickets using your Web3 wallet:
1

Connect Your Wallet

Connect the wallet holding the ticket NFT using MetaMask, WalletConnect, or Coinbase Wallet.
2

Navigate to Your Tickets

Go to My Tickets in your dashboard and select the ticket you want to transfer.
3

Initiate Transfer

Click Transfer Ticket and enter the recipient’s wallet address.
Triple-check the recipient address. NFT transfers are irreversible!
4

Confirm Transaction

Approve the transaction in your wallet and pay the gas fee (typically 0.001-0.01 MATIC on Polygon).
5

Transfer Complete

Once confirmed, the ticket NFT is transferred to the recipient’s wallet.

Transfer Restrictions

Event organizers can configure transfer restrictions:

Allowed Transfers

When allowTransfers = true (default):
Transfer Enabled
function _update(
    address to,
    uint256 tokenId,
    address auth
) internal override returns (address) {
    // Transfers are allowed
    return super._update(to, tokenId, auth);
}

Restricted Transfers

When allowTransfers = false:
Transfer Restricted
function _update(
    address to,
    uint256 tokenId,
    address auth
) internal override returns (address) {
    address from = _ownerOf(tokenId);
    
    // Allow minting but block transfers
    if (from != address(0) && to != address(0)) {
        revert("Transfers are disabled for this event");
    }
    
    return super._update(to, tokenId, auth);
}
Attempting to transfer a restricted ticket will fail and you’ll lose the gas fee.

Check Transfer Status

Verify if a ticket is transferable:
const eventContract = new ethers.Contract(
  contractAddress,
  ['function allowTransfers() view returns (bool)'],
  provider
);

const transfersAllowed = await eventContract.allowTransfers();

if (!transfersAllowed) {
  console.log('⚠️ Transfers are disabled for this event');
} else {
  console.log('✅ Tickets can be transferred');
}

ERC721 Transfer Functions

The EventTicket contract implements standard ERC721 transfer functions:
Safe Transfer
function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId
) public;

function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId,
    bytes memory data
) public;
Safely transfers ticket and checks if recipient can receive NFTs.

transferFrom

Basic Transfer
function transferFrom(
    address from,
    address to,
    uint256 tokenId
) public;
Basic transfer without recipient validation.
Always use safeTransferFrom to prevent sending tickets to contracts that can’t handle NFTs.

Transfer Validation

Before transfer, the contract validates:
  1. Ownership - Caller owns the ticket or is approved
  2. Transfer Policy - Event allows transfers (allowTransfers = true)
  3. Not Used - Ticket hasn’t been checked in yet
  4. Valid Recipient - Recipient address is not zero address

Post-Transfer Actions

Update Ticket Holder

After transferring a ticket, update the database record:
Update Holder
const response = await fetch(`/api/tickets/${ticketId}/update-holder`, {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`
  },
  body: JSON.stringify({
    newHolderAddress: recipientAddress
  })
});

Notify Recipient

Best practice: notify the recipient via email or message:
Notification Example
const notification = {
  userId: recipientUserId,
  title: 'Ticket Received',
  message: `You received a ticket for ${eventTitle}`,
  type: 'INFO'
};

await prisma.notification.create({ data: notification });

Gas Costs

Typical gas costs for ticket transfers on Polygon:
ActionGas LimitCost (MATIC)Cost (USD)
safeTransferFrom~75,0000.005~$0.01
Approve~50,0000.003~$0.006
setApprovalForAll~48,0000.003~$0.006
Polygon has very low gas fees, typically under $0.01 per transaction.

Security Best Practices

Verify Addresses

Always double-check recipient addresses. Use ENS names when possible.

Check Restrictions

Verify allowTransfers status before attempting transfer to avoid wasting gas.

Use Safe Transfer

Prefer safeTransferFrom over transferFrom to prevent loss of tickets.

Beware of Scams

Never approve unknown contracts. Only transfer through trusted interfaces.

Proof of Attendance (POA) Transfers

Unlike tickets, POA NFTs (minted after check-in) are soulbound and cannot be transferred:
POA Non-Transferable
// ProofOfAttendance.sol
function _update(
    address to,
    uint256 tokenId,
    address auth
) internal override returns (address) {
    address from = _ownerOf(tokenId);
    
    // Allow minting but prevent all transfers
    if (from != address(0) && to != address(0)) {
        revert("POAs are soulbound and non-transferable");
    }
    
    return super._update(to, tokenId, auth);
}
POAs are permanently bound to the wallet that checked in.

Bulk Transfers

Transfer multiple tickets at once:
Batch Transfer
const tokenIds = [101, 102, 103, 104, 105];
const recipient = '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb';

for (const tokenId of tokenIds) {
  const tx = await ticketContract.safeTransferFrom(
    currentOwner,
    recipient,
    tokenId
  );
  
  console.log(`Transferred ticket ${tokenId}: ${tx.hash}`);
  await tx.wait();
}

console.log(`✅ Transferred ${tokenIds.length} tickets`);
Each transfer is a separate transaction with individual gas costs.

Troubleshooting

Common reasons:
  1. Transfers disabled - Event has allowTransfers = false
  2. Not the owner - You don’t own this ticket
  3. Ticket used - Already checked in (if configured)
  4. Insufficient gas - Increase gas limit
  5. Invalid recipient - Zero address or blocked address
The recipient should:
  1. Add the token contract to their wallet (import custom token)
  2. Check the contract on blockchain explorer (Polygonscan)
  3. Refresh their GatePass dashboard
  4. View on OpenSea or other NFT marketplaces
NFT transfers are irreversible. To get the ticket back:
  • Ask the recipient to transfer it back to you
  • They will need to pay the gas fee for the return transfer
If you lose access to the wallet holding your ticket:
  • You cannot transfer the ticket (irreversible)
  • Contact event organizer for manual re-issue (at their discretion)
  • Always backup your seed phrase/private keys

Transfer History

Track ticket transfer history on-chain:
Get Transfer Events
const transferFilter = ticketContract.filters.Transfer(
  null,  // from (any address)
  null,  // to (any address)
  tokenId
);

const events = await ticketContract.queryFilter(
  transferFilter,
  0,  // from block 0
  'latest'
);

events.forEach(event => {
  console.log(`
    From: ${event.args.from}
    To: ${event.args.to}
    Block: ${event.blockNumber}
    Tx: ${event.transactionHash}
  `);
});

Next Steps

Check-In Process

Learn about the check-in process at events

Event Creation

Create your own event with custom transfer policies

Build docs developers (and LLMs) love