BSC Giveaway Contract Call Skill
1. Deployment information
- - Network: BSC (Binance Smart Chain mainnet, chainId = 56)
- Contract file: INLINECODE0
- Contract address: INLINECODE1
- Main dependencies:
IERC20, Ownable, ReentrancyGuard, internal TransferHelper library
Assumptions when calling:
- - You are already connected to a BSC mainnet RPC (for example
https://bsc-dataseed.binance.org) - Account balance and gas settings are handled by the caller
2. Core enums and structs (pass as uint in calls)
DistributionType
- -
0 = AVERAGE: equal share, each claim gets INLINECODE8 - INLINECODE9 = RANDOM: random share, a single claim is roughly in the range \(0 \sim 2 \times\) the average
ClaimRestriction
- -
0 = PUBLIC: public, no additional restriction - INLINECODE11 = TOKEN_HOLDER: only addresses holding
restrictionToken with balance ≥ INLINECODE13 - INLINECODE14 = WHITELIST: only whitelisted addresses can claim
GiveawayInfo
- -
token: token address for the giveaway, address(0) means BNB - INLINECODE17 : creator address
- INLINECODE18 : current remaining total giveaway amount in the contract (after creation fee is deducted)
- INLINECODE19 : current remaining claimable slots
- INLINECODE20 : distribution type (0/1)
- INLINECODE21 : claim restriction type (0/1/2)
- INLINECODE22 : restriction token address (only meaningful for TOKEN_HOLDER)
- INLINECODE23 : minimum token balance required
- INLINECODE24 : expiration timestamp (seconds)
3. Write function cheatsheet
3.1 Create giveaway createGiveaway
Signature:
CODEBLOCK0
Key constraints:
- - INLINECODE26
- INLINECODE27
- INLINECODE28
- INLINECODE29 ∈ {0,1}
- INLINECODE30 ∈ {0,1,2}
- If
restriction == TOKEN_HOLDER (1):
-
restrictionToken != address(0)
- INLINECODE33
Fees and transfers:
- - Fee:
feeAmount = (amount / 1000) * FEERATE, sent directly to INLINECODE35 - Actual amount entering the contract: INLINECODE36
- If
token == address(0) (BNB giveaway):
- Transaction
msg.value >= amount
-
feeAmount and
sendAmount are both paid in BNB
- - If
token != address(0) (ERC20 giveaway):
- Transaction
msg.value == 0
- You must first
approve on-chain:
-
approve(contract, amount) (user → contract)
- The contract internally uses
safeTransferFrom to send
feeAmount to
FEEADDRESS and
sendAmount to the contract itself
3.2 Claim giveaway claimGiveaway
CODEBLOCK1
Internal checks:
- -
giveawayInfos[id].amount != 0: giveaway exists and has remaining amount - Caller has not claimed yet: INLINECODE51
- Not expired: INLINECODE52
- TOKEN_HOLDER: check INLINECODE53
- WHITELIST: INLINECODE54
Distribution logic:
- If
count == 1: send all remaining amount to the current claimer
- Otherwise, single claim amount is
sendAmount = amount / count
- If
count == 1: also send all remaining amount
- Otherwise:
-
randomNumber = uint8(keccak256(...)) % 100
- INLINECODE59
3.3 Withdraw expired giveaway withdrawExpiredGiveaway
CODEBLOCK2
Constraints:
- - INLINECODE61
- INLINECODE62
- INLINECODE63
Withdrawal fee:
- - INLINECODE64
- INLINECODE65
- Transfer logic also distinguishes BNB vs ERC20
3.4 Whitelist management
CODEBLOCK3
Constraints:
- - Only the giveaway creator: INLINECODE66
- And the giveaway must be of WHITELIST type: INLINECODE67
4. Read function cheatsheet
CODEBLOCK4
Key points of canClaim:
- - Returns
false if amount is 0, already claimed, or INLINECODE70 - TOKEN_HOLDER: checks token balance
- WHITELIST: checks whitelist
- Otherwise returns
true (PUBLIC)
5. Script / frontend usage example (ethers.js)
Assume you already have a provider / signer and have loaded the compiled ABI:
CODEBLOCK5
When integrating in a frontend or script:
- - Read functions (
getGiveawayInfo, canClaim, isInWhitelist) can use a provider instance; - Write functions (
createGiveaway, claimGiveaway, withdrawExpiredGiveaway, whitelist add/remove) must use a signer with signing capability; - For BNB giveaways you must pass BNB equal to
amount via value; for ERC20 giveaways you must approve beforehand.
7. ABI information and minimal examples
- - Full ABI source: the JSON generated after compiling
contracts/contracts/Giveaway.sol in this repo (for example artifacts/.../Giveaway.json); in scripts/frontends you should generally import the abi field from that file. - Purpose of this section: provide a minimal ABI fragment for quick debugging or building a minimal frontend/script when you cannot directly access the compiled artifacts. It is not guaranteed to stay perfectly in sync with future contract upgrades.
7.1 Key event fragments
CODEBLOCK6
7.2 Common function fragments
Only the most common read/write function signatures are listed below, to make it easy to construct ethers.Contract / web3.eth.Contract. For the full ABI, always refer to the build artifacts.
CODEBLOCK7
The fragments above can be combined with the TypeScript example earlier, for example:
CODEBLOCK8
6. Relationship with existing giveaway-protocol skill
- -
giveaway-protocol focuses more on the protocol-level description (enum semantics, logical constraints, general call conventions); - INLINECODE92 is specifically about this concrete contract deployed on BSC mainnet (fixed contract address + specific network info + call examples).
When you need “the contract address and direct on-chain interaction”, you should prefer this skill.
If you need more complete error descriptions or protocol details, you can also refer to giveaway-protocol’s reference.md.
BSC 空投合约调用技能
1. 部署信息
- - 网络: BSC (币安智能链主网, chainId = 56)
- 合约文件: contracts/contracts/Giveaway.sol
- 合约地址: 0xc9Db158004fEFe15633eF2Ac3C3eA209e58Db5B9
- 主要依赖: IERC20, Ownable, ReentrancyGuard, 内部 TransferHelper 库
调用时的假设条件:
- - 您已连接到 BSC 主网 RPC (例如 https://bsc-dataseed.binance.org)
- 账户余额和 gas 设置由调用方处理
2. 核心枚举和结构体 (调用时以 uint 形式传入)
DistributionType
- - 0 = AVERAGE: 平均分配,每次领取获得 amount / count
- 1 = RANDOM: 随机分配,单次领取大致在 \(0 \sim 2 \times\) 平均值的范围内
ClaimRestriction
- - 0 = PUBLIC: 公开,无额外限制
- 1 = TOKEN_HOLDER: 仅限持有 restrictionToken 且余额 ≥ minTokenBalance 的地址
- 2 = WHITELIST: 仅限白名单地址领取
GiveawayInfo
- - token: 空投的代币地址,address(0) 表示 BNB
- sender: 创建者地址
- amount: 合约中当前剩余的空投总金额 (扣除创建费后)
- count: 当前剩余的可领取名额
- distributionType: 分配类型 (0/1)
- restriction: 领取限制类型 (0/1/2)
- restrictionToken: 限制代币地址 (仅 TOKEN_HOLDER 类型有意义)
- minTokenBalance: 所需的最低代币余额
- lastDate: 过期时间戳 (秒)
3. 写入函数速查表
3.1 创建空投 createGiveaway
签名:
solidity
function createGiveaway(
address token,
uint256 amount,
uint256 count,
DistributionType distributionType,
ClaimRestriction restriction,
address restrictionToken,
uint256 minTokenBalance,
string memory content,
uint256 lastDate
) public payable
关键约束:
- - bytes(content).length < 128
- amount > 0
- amount / count > 0
- distributionType ∈ {0,1}
- restriction ∈ {0,1,2}
- 如果 restriction == TOKEN_HOLDER (1):
- restrictionToken != address(0)
- minTokenBalance > 0
费用和转账:
- - 费用: feeAmount = (amount / 1000) * FEERATE,直接发送至 FEEADDRESS
- 实际进入合约的金额: sendAmount = amount - feeAmount
- 如果 token == address(0) (BNB 空投):
- 交易 msg.value >= amount
- feeAmount 和 sendAmount 均以 BNB 支付
- - 如果 token != address(0) (ERC20 空投):
- 交易 msg.value == 0
- 您必须先在链上执行 approve:
- approve(contract, amount) (用户 → 合约)
- 合约内部使用 safeTransferFrom 将 feeAmount 发送至 FEEADDRESS,将 sendAmount 发送至合约自身
3.2 领取空投 claimGiveaway
solidity
function claimGiveaway(uint256 id) public nonReentrant
内部检查:
- - giveawayInfos[id].amount != 0: 空投存在且有剩余金额
- 调用者尚未领取: giveawayInfoexist[id][msg.sender] == 0
- 未过期: giveawayInfos[id].lastDate > block.timestamp
- TOKENHOLDER: 检查 IERC20(restrictionToken).balanceOf(msg.sender) >= minTokenBalance
- WHITELIST: giveawayWhitelist[id][msg.sender] == true
分配逻辑:
- 如果 count == 1: 将所有剩余金额发送给当前领取者
- 否则,单次领取金额为 sendAmount = amount / count
- 如果 count == 1: 同样发送所有剩余金额
- 否则:
- randomNumber = uint8(keccak256(...)) % 100
- sendAmount = (amount / count
2) randomNumber / 100
3.3 提取过期空投 withdrawExpiredGiveaway
solidity
function withdrawExpiredGiveaway(uint256 id) public nonReentrant
约束:
- - giveawayInfos[id].amount != 0
- giveawayInfos[id].sender == msg.sender
- giveawayInfos[id].lastDate < block.timestamp
提取费用:
- - feeAmount = (amount / 1000) * EXPIREDRATE
- sendAmount = amount - feeAmount
- 转账逻辑同样区分 BNB 和 ERC20
3.4 白名单管理
solidity
function addToWhitelist(uint256 giveawayId, address[] memory addresses) public
function removeFromWhitelist(uint256 giveawayId, address[] memory addresses) public
约束:
- - 仅限空投创建者: giveawayInfos[giveawayId].sender == msg.sender
- 且空投类型必须为 WHITELIST: restriction == ClaimRestriction.WHITELIST
4. 读取函数速查表
solidity
function getGiveawayInfo(uint256 id) external view returns (GiveawayInfo memory)
function isInWhitelist(uint256 giveawayId, address user) external view returns (bool)
function canClaim(uint256 id, address user) external view returns (bool)
canClaim 的关键点:
- - 如果金额为 0、已领取或 block.timestamp >= lastDate,则返回 false
- TOKEN_HOLDER: 检查代币余额
- WHITELIST: 检查白名单
- 否则返回 true (PUBLIC)
5. 脚本/前端使用示例 (ethers.js)
假设您已有 provider / signer 并已加载编译后的 ABI:
ts
import { ethers } from ethers;
import GiveawayAbi from ../artifacts/contracts/Giveaway.sol/Giveaway.json;
const GIVEAWAY_ADDRESS = 0xc9Db158004fEFe15633eF2Ac3C3eA209e58Db5B9;
// 创建合约实例 (读取或写入)
export function getGiveawayContract(providerOrSigner: ethers.Signer | ethers.providers.Provider) {
return new ethers.Contract(GIVEAWAY_ADDRESS, GiveawayAbi.abi, providerOrSigner);
}
// 示例: 创建 BNB 空投
export async function createBnbGiveaway(
signer: ethers.Signer,
params: {
amountWei: ethers.BigNumberish;
count: number;
distributionType: 0 | 1;
restriction: 0 | 1 | 2;
restrictionToken: string;
minTokenBalance: ethers.BigNumberish;
content: string;
lastDate: number;
}
) {
const contract = getGiveawayContract(signer);
const tx = await contract.createGiveaway(
ethers.constants.AddressZero,
params.amountWei,
params.count,
params.distributionType,
params.restriction,
params.restrictionToken,
params.minTokenBalance,
params.content,
params.lastDate,
{ value: params.amountWei }
);
return tx.wait();
}
// 示例: 领取空投
export async function claimGiveaway(signer: ethers.Signer, id: number) {
const contract = getGiveawayContract(signer);
const tx = await contract.claimGiveaway(id);
return tx.wait();
}
在前端或脚本中集成时:
- - 读取函数 (getGiveawayInfo, canClaim, isInWhitelist) 可使用 provider 实例;
- 写入函数 (createGiveaway, claimGiveaway, withdrawExpiredGiveaway, 白名单添加/移除) 必须使用具有签名能力的 signer;
- 对于 BNB 空投,您必须通过 value 传递等于 amount 的 BNB;对于 ERC20 空投,您必须事先执行 approve