/install giveaway-skills
BSC Giveaway Contract Call Skill
1. Deployment information
- Network: BSC (Binance Smart Chain mainnet, chainId = 56)
- Contract file:
contracts/contracts/Giveaway.sol - Contract address:
0xc9Db158004fEFe15633eF2Ac3C3eA209e58Db5B9 - Main dependencies:
IERC20,Ownable,ReentrancyGuard, internalTransferHelperlibrary
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 getsamount / count1= RANDOM: random share, a single claim is roughly in the range (0 \sim 2 imes) the average
ClaimRestriction
0= PUBLIC: public, no additional restriction1= TOKEN_HOLDER: only addresses holdingrestrictionTokenwith balance ≥minTokenBalance2= WHITELIST: only whitelisted addresses can claim
GiveawayInfo
token: token address for the giveaway,address(0)means BNBsender: creator addressamount: current remaining total giveaway amount in the contract (after creation fee is deducted)count: current remaining claimable slotsdistributionType: distribution type (0/1)restriction: claim restriction type (0/1/2)restrictionToken: restriction token address (only meaningful for TOKEN_HOLDER)minTokenBalance: minimum token balance requiredlastDate: expiration timestamp (seconds)
3. Write function cheatsheet
3.1 Create giveaway createGiveaway
Signature:
function createGiveaway(
address token,
uint256 amount,
uint256 count,
DistributionType distributionType,
ClaimRestriction restriction,
address restrictionToken,
uint256 minTokenBalance,
string memory content,
uint256 lastDate
) public payable
Key constraints:
bytes(content).length \x3C 128amount > 0amount / count > 0distributionType∈ {0,1}restriction∈ {0,1,2}- If
restriction == TOKEN_HOLDER (1):restrictionToken != address(0)minTokenBalance > 0
Fees and transfers:
- Fee:
feeAmount = (amount / 1000) * FEERATE, sent directly toFEEADDRESS - Actual amount entering the contract:
sendAmount = amount - feeAmount - If
token == address(0)(BNB giveaway):- Transaction
msg.value >= amount feeAmountandsendAmountare both paid in BNB
- Transaction
- If
token != address(0)(ERC20 giveaway):- Transaction
msg.value == 0 - You must first
approveon-chain:approve(contract, amount)(user → contract)
- The contract internally uses
safeTransferFromto sendfeeAmounttoFEEADDRESSandsendAmountto the contract itself
- Transaction
3.2 Claim giveaway claimGiveaway
function claimGiveaway(uint256 id) public nonReentrant
Internal checks:
giveawayInfos[id].amount != 0: giveaway exists and has remaining amount- Caller has not claimed yet:
giveawayInfo_exist[id][msg.sender] == 0 - Not expired:
giveawayInfos[id].lastDate > block.timestamp - TOKEN_HOLDER: check
IERC20(restrictionToken).balanceOf(msg.sender) >= minTokenBalance - WHITELIST:
giveawayWhitelist[id][msg.sender] == true
Distribution logic:
- AVERAGE:
- If
count == 1: send all remaining amount to the current claimer - Otherwise, single claim amount is
sendAmount = amount / count
- If
- RANDOM:
- If
count == 1: also send all remaining amount - Otherwise:
randomNumber = uint8(keccak256(...)) % 100sendAmount = (amount / count * 2) * randomNumber / 100
- If
3.3 Withdraw expired giveaway withdrawExpiredGiveaway
function withdrawExpiredGiveaway(uint256 id) public nonReentrant
Constraints:
giveawayInfos[id].amount != 0giveawayInfos[id].sender == msg.sendergiveawayInfos[id].lastDate \x3C block.timestamp
Withdrawal fee:
feeAmount = (amount / 1000) * EXPIREDRATEsendAmount = amount - feeAmount- Transfer logic also distinguishes BNB vs ERC20
3.4 Whitelist management
function addToWhitelist(uint256 giveawayId, address[] memory addresses) public
function removeFromWhitelist(uint256 giveawayId, address[] memory addresses) public
Constraints:
- Only the giveaway creator:
giveawayInfos[giveawayId].sender == msg.sender - And the giveaway must be of WHITELIST type:
restriction == ClaimRestriction.WHITELIST
4. Read function cheatsheet
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)
Key points of canClaim:
- Returns
falseif amount is 0, already claimed, orblock.timestamp >= lastDate - 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:
import { ethers } from "ethers";
import GiveawayAbi from "../artifacts/contracts/Giveaway.sol/Giveaway.json";
const GIVEAWAY_ADDRESS = "0xc9Db158004fEFe15633eF2Ac3C3eA209e58Db5B9";
// Create contract instance (read or write)
export function getGiveawayContract(providerOrSigner: ethers.Signer | ethers.providers.Provider) {
return new ethers.Contract(GIVEAWAY_ADDRESS, GiveawayAbi.abi, providerOrSigner);
}
// Example: create a BNB giveaway
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();
}
// Example: claim a giveaway
export async function claimGiveaway(signer: ethers.Signer, id: number) {
const contract = getGiveawayContract(signer);
const tx = await contract.claimGiveaway(id);
return tx.wait();
}
When integrating in a frontend or script:
- Read functions (
getGiveawayInfo,canClaim,isInWhitelist) can use aproviderinstance; - Write functions (
createGiveaway,claimGiveaway,withdrawExpiredGiveaway, whitelist add/remove) must use asignerwith signing capability; - For BNB giveaways you must pass BNB equal to
amountviavalue; for ERC20 giveaways you mustapprovebeforehand.
7. ABI information and minimal examples
- Full ABI source: the JSON generated after compiling
contracts/contracts/Giveaway.solin this repo (for exampleartifacts/.../Giveaway.json); in scripts/frontends you should generally import theabifield 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
[
{
"type": "event",
"name": "GiveawayCreated",
"anonymous": false,
"inputs": [
{ "indexed": false, "name": "id", "type": "uint256" },
{ "indexed": false, "name": "token", "type": "address" },
{ "indexed": false, "name": "sender", "type": "address" },
{ "indexed": false, "name": "amount", "type": "uint256" },
{ "indexed": false, "name": "count", "type": "uint256" },
{ "indexed": false, "name": "distributionType", "type": "uint8" },
{ "indexed": false, "name": "restriction", "type": "uint8" },
{ "indexed": false, "name": "restrictionToken", "type": "address" },
{ "indexed": false, "name": "minTokenBalance", "type": "uint256" },
{ "indexed": false, "name": "content", "type": "string" },
{ "indexed": false, "name": "lastDate", "type": "uint256" }
]
},
{
"type": "event",
"name": "GiveawayClaimed",
"anonymous": false,
"inputs": [
{ "indexed": false, "name": "id", "type": "uint256" },
{ "indexed": false, "name": "sender", "type": "address" },
{ "indexed": false, "name": "count", "type": "uint256" },
{ "indexed": false, "name": "amount", "type": "uint256" }
]
},
{
"type": "event",
"name": "GiveawayWithdrawn",
"anonymous": false,
"inputs": [
{ "indexed": false, "name": "id", "type": "uint256" }
]
},
{
"type": "event",
"name": "WhitelistAdded",
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "giveawayId", "type": "uint256" },
{ "indexed": false, "name": "addresses", "type": "address[]" }
]
},
{
"type": "event",
"name": "WhitelistRemoved",
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "giveawayId", "type": "uint256" },
{ "indexed": false, "name": "addresses", "type": "address[]" }
]
}
]
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.
[
{
"type": "function",
"stateMutability": "payable",
"name": "createGiveaway",
"inputs": [
{ "name": "token", "type": "address" },
{ "name": "amount", "type": "uint256" },
{ "name": "count", "type": "uint256" },
{ "name": "distributionType", "type": "uint8" },
{ "name": "restriction", "type": "uint8" },
{ "name": "restrictionToken", "type": "address" },
{ "name": "minTokenBalance", "type": "uint256" },
{ "name": "content", "type": "string" },
{ "name": "lastDate", "type": "uint256" }
],
"outputs": []
},
{
"type": "function",
"stateMutability": "nonpayable",
"name": "claimGiveaway",
"inputs": [
{ "name": "id", "type": "uint256" }
],
"outputs": []
},
{
"type": "function",
"stateMutability": "nonpayable",
"name": "withdrawExpiredGiveaway",
"inputs": [
{ "name": "id", "type": "uint256" }
],
"outputs": []
},
{
"type": "function",
"stateMutability": "nonpayable",
"name": "addToWhitelist",
"inputs": [
{ "name": "giveawayId", "type": "uint256" },
{ "name": "addresses", "type": "address[]" }
],
"outputs": []
},
{
"type": "function",
"stateMutability": "nonpayable",
"name": "removeFromWhitelist",
"inputs": [
{ "name": "giveawayId", "type": "uint256" },
{ "name": "addresses", "type": "address[]" }
],
"outputs": []
},
{
"type": "function",
"stateMutability": "view",
"name": "getGiveawayInfo",
"inputs": [
{ "name": "id", "type": "uint256" }
],
"outputs": [
{
"components": [
{ "name": "token", "type": "address" },
{ "name": "sender", "type": "address" },
{ "name": "amount", "type": "uint256" },
{ "name": "count", "type": "uint256" },
{ "name": "distributionType", "type": "uint8" },
{ "name": "restriction", "type": "uint8" },
{ "name": "restrictionToken", "type": "address" },
{ "name": "minTokenBalance", "type": "uint256" },
{ "name": "lastDate", "type": "uint256" }
],
"type": "tuple"
}
]
},
{
"type": "function",
"stateMutability": "view",
"name": "canClaim",
"inputs": [
{ "name": "id", "type": "uint256" },
{ "name": "user", "type": "address" }
],
"outputs": [
{ "type": "bool" }
]
},
{
"type": "function",
"stateMutability": "view",
"name": "isInWhitelist",
"inputs": [
{ "name": "giveawayId", "type": "uint256" },
{ "name": "user", "type": "address" }
],
"outputs": [
{ "type": "bool" }
]
}
]
The fragments above can be combined with the TypeScript example earlier, for example:
const abi = [...eventsFragment, ...functionsFragment];
const contract = new ethers.Contract(GIVEAWAY_ADDRESS, abi, signerOrProvider);
6. Relationship with existing giveaway-protocol skill
giveaway-protocolfocuses more on the protocol-level description (enum semantics, logical constraints, general call conventions);giveaway-skillsis 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.
- 确保已安装 OpenClaw(本地或 Docker 部署)
- 在对话框中输入安装命令:
/install giveaway-skills - 安装完成后,直接呼叫该 Skill 的名称或使用
/giveaway-skills触发 - 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
Giveaway Skills 是什么?
Call guide and best practices for the BSC on-chain giveaway contract based on contracts/contracts/Giveaway.sol, including contract address, core method signa... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 287 次。
如何安装 Giveaway Skills?
在 OpenClaw 或 Claude Code 对话框中运行命令「/install giveaway-skills」即可一键安装,无需额外配置。
Giveaway Skills 是免费的吗?
是的,Giveaway Skills 完全免费(开源免费),可自由下载、安装和使用。
Giveaway Skills 支持哪些平台?
Giveaway Skills 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。
谁开发了 Giveaway Skills?
由 Franck.S(@franckstone)开发并维护,当前版本 v0.1.0。