Goat27 合约函数文档

本文档列出 src/Goat27/Goat27.sol 中所有外部可调用函数的签名、用途、参数与返回值。
权限说明:OWNER 表示需要 Ownable.onlyOwnerANYONE 表示任何地址可调用;WHITELISTED 表示买卖税白名单中的地址可被自动豁免(非权限,而是状态查询)。

合约类型:ERC20 + ERC20Permit + Ownable,在 PancakeSwap V2 交易对上自动按 5% 买卖税收取并按 20/80 销毁/兑换 USDT;同时叠加 5%/天的复利通缩。


1. ERC20 标准函数

1.1 name

  • 签名:function name() external view returns (string memory)
  • 权限:ANYONE
  • 用途:返回代币名称,固定为 "GOAT27"
  • 参数:无。
  • 返回值:string memory 代币名称。

1.2 symbol

  • 签名:function symbol() external view returns (string memory)
  • 权限:ANYONE
  • 用途:返回代币符号,固定为 "GOAT27"
  • 参数:无。
  • 返回值:string memory 代币符号。

1.3 decimals

  • 签名:function decimals() external view returns (uint8)
  • 权限:ANYONE
  • 用途:返回代币精度,固定为 18(在构造函数中硬编码到不可变量 _decimals)。
  • 参数:无。
  • 返回值:uint8 代币精度。

1.4 totalSupply

  • 签名:function totalSupply() external view returns (uint256)
  • 权限:ANYONE
  • 用途:返回代币总供应量。初始供应 1_000_000_000 * 1e18 在构造函数中一次性铸造给 initialHolder_,之后只有 5% 买卖税会通过销毁逐步减少总量(每次税费分配销毁 burnAmount)。
  • 参数:无。
  • 返回值:uint256 当前总供应量(18 位小数)。

1.5 balanceOf

  • 签名:function balanceOf(address account) external view returns (uint256)
  • 权限:ANYONE
  • 用途:返回指定账户的通缩后余额(实时计算,非 OZ 原生 balanceOf)。
  • 参数:
    • account:要查询的账户地址。
  • 返回值:uint256 该账户的当前可用余额(18 位小数)。白名单账户返回 _deflation.baseBalance(锁定值);非白名单账户按复利通缩公式折算到当前时间。
  • 特殊语义:
    • _deflation.baseBalance == 0 时直接返回 OZ 原生 balanceOf(避免对刚 mint 的地址做空折算)。
    • 白名单账户返回 baseBalance,不随时间衰减
    • 通缩算法:N 天未动的余额衰减为 baseBalance * 0.95^N(复利,不是线性)。任何账户的转账都会立刻折算到当前时间。

1.6 allowance

  • 签名:function allowance(address owner, address spender) external view returns (uint256)
  • 权限:ANYONE
  • 用途:返回 spenderowner 的授权额度,语义与标准 ERC20 一致。
  • 参数:
    • owner:被授权人地址。
    • spender:被授权使用方地址。
  • 返回值:uint256 当前授权额度。

1.7 transfer

  • 签名:function transfer(address to, uint256 value) external returns (bool)
  • 权限:ANYONE(可被买卖税自动按比例扣减)
  • 用途:转账指定数量的代币。内部调用 _update(from, to, value)。若为买卖转账则按 5% 收税,否则按当前通缩基线扣减。详见 _update 逻辑。
  • 参数:
    • to:接收方地址,不能为零地址。
    • value:转账数量(18 位小数)。
  • 返回值:bool 始终为 true(失败会 revert)。
  • 错误:
    • InsufficientBalance(have, want)from 通缩后余额不足,且差额不属于”最近 5 分钟变化量”的白名单区间时抛出。
    • InsufficientOzBalance(have, want)from 是白名单,但 OZ 原生余额不足时抛出。

1.8 approve

  • 签名:function approve(address spender, uint256 value) external returns (bool)
  • 权限:ANYONE
  • 用途:授权 spender 最多可使用调用者 value 数量的代币。语义与标准 ERC20 一致。
  • 参数:
    • spender:被授权方地址。
    • value:授权额度(若要取消授权传 0)。
  • 返回值:bool 始终为 true
  • 事件:Approval(owner, spender, value)(OZ 标准)。

1.9 transferFrom

  • 签名:function transferFrom(address from, address to, uint256 value) external returns (bool)
  • 权限:ANYONE(需先被 from 通过 approve 授权)
  • 用途:由第三方代替 from 转账给 to,会先扣减授权额度再走 _update
  • 参数:
    • from:代币发送方地址。
    • to:接收方地址。
    • value:转账数量。
  • 返回值:bool 始终为 true
  • 错误:同 transfer

1.10 permit

  • 签名:function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external
  • 权限:ANYONE(通过 EIP-2612 离线签名授权)
  • 用途:通过签名一次性完成授权,无需先发送 approve 交易。来自 ERC20Permit
  • 参数:同 EIP-2612 标准。
  • 返回值:无。

1.11 nonces

  • 签名:function nonces(address owner) external view returns (uint256)
  • 权限:ANYONE
  • 用途:返回 EIP-2612 permit 防重放序号。
  • 参数:
    • owner:查询的账户地址。
  • 返回值:uint256 该账户当前的 permit nonce。

1.12 DOMAIN_SEPARATOR

  • 签名:function DOMAIN_SEPARATOR() external view returns (bytes32)
  • 权限:ANYONE
  • 用途:返回 EIP-712 域分隔符,用于 permit 签名验证。

2. 公共函数(税费分配)

2.1 triggerDistribution

  • 签名:function triggerDistribution() external
  • 权限:ANYONE
  • 用途:手动触发一次税费分配。检查 accumulatedTax,若为 0 则直接返回;否则执行”销毁 20% + 80% 在底池兑换成 USDT + USDT 一半转给 lpDividendAddress 并触发 LP 池分配 + 另一半转给 ecoFundAddress“。整个过程通过 whenNotDistributing 修饰器串行化。
  • 参数:无。
  • 返回值:无。
  • 错误:
    • OnlySelf() 当合约内 _doDistributiontry/catch 直接调用时抛出(msg.sender != address(this))。外部调用 triggerDistribution 不会触发此错误,因为内部通过 this._doDistribution() 转发。
    • string("distribution in progress") 当已有一次分配正在进行时抛出(防御性,正常不应触发)。

3. 管理员函数:地址设置

3.1 setLiquidityPair

  • 签名:function setLiquidityPair(address pair) external
  • 权限:OWNER
  • 用途:设置 PancakeSwap V2 的 GOAT27-USDT 交易对地址。会自动维护 deflationWhitelist:从旧的 Pair 移除白名单,新的 Pair 加入白名单(避免 Pair 自身的余额被通缩)。
  • 参数:
    • pair:新的 Pair 地址,可以为零地址(取消设置)。
  • 返回值:无。
  • 事件:LiquidityPairUpdated(previousPair, newPair)

3.2 setLpDividendAddress

  • 签名:function setLpDividendAddress(address newAddress) external
  • 权限:OWNER
  • 用途:设置 LP 分发地址(典型为 Goat27LPStaking 合约)。每次税费分配时,USDT 一半会先转给该地址,然后调用其 triggerDistribution。会自动维护 deflationWhitelist
  • 参数:
    • newAddress:新的 LP 分发地址,不能为零地址
  • 返回值:无。
  • 错误:ZeroAddress()newAddress 为零地址时抛出。
  • 事件:LpDividendAddressUpdated(previousAddress, newAddress)

3.3 setEcoFundAddress

  • 签名:function setEcoFundAddress(address newAddress) external
  • 权限:OWNER
  • 用途:设置生态基金地址。每次税费分配时,USDT 另一半会转给该地址。不能为零地址
  • 参数:
    • newAddress:新的生态基金地址。
  • 返回值:无。
  • 错误:ZeroAddress()newAddress 为零地址时抛出。
  • 事件:EcoFundAddressUpdated(newAddress)

3.4 setRouter

  • 签名:function setRouter(address newRouter) external
  • 权限:OWNER
  • 用途:更新 PancakeSwap V2 路由合约地址。会自动把旧路由的授权清零(forceApprove(old, 0)),新路由的授权在下次 swap 时按需给出。
  • 参数:
    • newRouter:新的路由地址,不能为零地址
  • 返回值:无。
  • 错误:ZeroRouterAddress()newRouter 为零地址时抛出。
  • 事件:RouterUpdated(previousRouter, newRouter)

3.5 setUsdt

  • 签名:function setUsdt(address newUsdt) external
  • 权限:OWNER
  • 用途:更新 USDT 合约地址。仅在 USDT 合约迁移或测试网切换时使用。
  • 参数:
    • newUsdt:新的 USDT 地址,不能为零地址
  • 返回值:无。
  • 错误:ZeroAddress()newUsdt 为零地址时抛出。
  • 事件:UsdtUpdated(previousUsdt, newUsdt)

4. 管理员函数:白名单

4.1 setTaxWhitelist

  • 签名:function setTaxWhitelist(address account, bool whitelisted) external
  • 权限:OWNER
  • 用途:将指定账户加入或移出”买卖税白名单”。白名单账户之间互相转账不收 5% 税,也不触发对方收税。
  • 参数:
    • account:目标账户地址。
    • whitelisted:true 加入,false 移除。
  • 返回值:无。
  • 事件:TaxWhitelistUpdated(account, whitelisted)

4.2 setTaxWhitelistBatch

  • 签名:function setTaxWhitelistBatch(address[] calldata accounts, bool whitelisted) external
  • 权限:OWNER
  • 用途:批量设置买卖税白名单。
  • 参数:
    • accounts:目标账户地址数组。
    • whitelisted:统一的目标状态。
  • 返回值:无。
  • 事件:对每个账户各触发一次 TaxWhitelistUpdated

4.3 setDeflationWhitelist

  • 签名:function setDeflationWhitelist(address account, bool whitelisted) external
  • 权限:OWNER
  • 用途:将指定账户加入或移出”通缩白名单”。白名单账户的余额按 _deflation.baseBalance 锁定,不随时间衰减;首次加入白名单时会将当前余额快照到 baseBalance,以确保 balanceOf() 返回值不变。
  • 参数:
    • account:目标账户地址。
    • whitelisted:目标状态。
  • 返回值:无。
  • 特殊语义:若 deflationWhitelist[account] == whitelisted(状态未变化)则直接返回,不修改 storage。
  • 事件:DeflationWhitelistUpdated(account, whitelisted)

4.4 setDeflationWhitelistBatch

  • 签名:function setDeflationWhitelistBatch(address[] calldata accounts, bool whitelisted) external
  • 权限:OWNER
  • 用途:批量设置通缩白名单,跳过状态未变化的账户。
  • 参数:
    • accounts:目标账户地址数组。
    • whitelisted:统一的目标状态。
  • 返回值:无。
  • 事件:对每个状态实际变化的账户各触发一次 DeflationWhitelistUpdated

4.5 addToWhitelist

  • 签名:function addToWhitelist(address account) external
  • 权限:OWNER
  • 用途:一次性把指定账户加入”双白名单”(同时加入买卖税白名单与通缩白名单)。幂等:重复调用对 tax whitelist 总是 set true 并 emit 事件;deflation whitelist 若已存在则只 emit 事件,不重写 storage。
  • 参数:
    • account:目标账户地址,不能为零地址
  • 返回值:无。
  • 错误:ZeroAddress()account 为零地址时抛出。
  • 事件:TaxWhitelistUpdated(account, true) + DeflationWhitelistUpdated(account, true)

4.6 addToWhitelistBatch

  • 签名:function addToWhitelistBatch(address[] calldata accounts) external
  • 权限:OWNER
  • 用途:批量版 addToWhitelist。数组中任一为零地址都会导致整个调用 revert。
  • 参数:
    • accounts:目标账户地址数组。
  • 返回值:无。
  • 错误:ZeroAddress() 当数组中任一地址为零地址时抛出。

5. 视图函数

5.1 deflationBaseBalance

  • 签名:function deflationBaseBalance(address account) external view returns (uint256)
  • 权限:ANYONE
  • 用途:返回指定账户的通缩基线余额(_deflation.baseBalance,通缩计算的起点)。非白名单账户的”实际余额”会随时间从该值开始衰减。
  • 参数:
    • account:查询的账户地址。
  • 返回值:uint256 基线余额(18 位小数)。

5.2 deflationBaseTime

  • 签名:function deflationBaseTime(address account) external view returns (uint256)
  • 权限:ANYONE
  • 用途:返回指定账户基线余额的更新时间戳(_deflation.baseUpdateTime),即”通缩从该时间开始计算”的时间点。
  • 参数:
    • account:查询的账户地址。
  • 返回值:uint256 基线时间戳(秒)。

5.3 deflationStopTime

  • 签名:function deflationStopTime() external pure returns (uint256)
  • 权限:ANYONE
  • 用途:返回通缩停止时间戳常量 1801843200(2027-02-05 16:00:00 UTC)。超过该时间后,所有账户的余额衰减被冻结在”截至该时间”的值上。
  • 返回值:uint256 通缩停止时间戳。

5.4 usdt

  • 签名:function usdt() external view returns (address)
  • 权限:ANYONE
  • 用途:返回当前生效的 USDT 合约地址(从不可变量 _usdt 读出)。
  • 返回值:address USDT 合约地址。

5.5 blackHole

  • 签名:function blackHole() external pure returns (address)
  • 权限:ANYONE
  • 用途:返回黑洞销毁地址常量 0x000000000000000000000000000000000000dEaD(税费销毁与直推无主奖励的接收方)。
  • 返回值:address 黑洞地址。

5.6 usdtForwarder

  • 签名:function usdtForwarder() external view returns (address)
  • 权限:ANYONE
  • 用途:返回部署时自动创建的 USDT 中转合约地址(USDTForwarder)。该合约用于在税费分配时接收 swap 后的 USDT,再 withdraw 到主合约,从而绕过”to == token0/token1”的 pair mock 限制。
  • 返回值:address USDTForwarder 地址。

5.7 liquidityPair

  • 签名:function liquidityPair() external view returns (address)
  • 权限:ANYONE
  • 用途:返回当前设置的 PancakeSwap V2 Pair 地址(可能为零地址,若尚未设置)。

5.8 lpDividendAddress

  • 签名:function lpDividendAddress() external view returns (address)
  • 权限:ANYONE
  • 用途:返回当前设置的 LP 分发地址(可能为零地址)。

5.9 ecoFundAddress

  • 签名:function ecoFundAddress() external view returns (address)
  • 权限:ANYONE
  • 用途:返回当前设置的生态基金地址(可能为零地址)。

5.10 router

  • 签名:function router() external view returns (address)
  • 权限:ANYONE
  • 用途:返回当前设置的 PancakeSwap Router 地址。

5.11 accumulatedTax

  • 签名:function accumulatedTax() external view returns (uint256)
  • 权限:ANYONE
  • 用途:返回当前累计未分配的代币税(每次买卖税 5% 中的 100% 全部累加到此,达到 TAX_THRESHOLD = 10000 * 1e18 时自动分配一次)。

5.12 taxWhitelist

  • 签名:function taxWhitelist(address account) external view returns (bool)
  • 权限:ANYONE
  • 用途:查询指定账户是否在买卖税白名单中(白名单内买卖免 5% 税)。

5.13 deflationWhitelist

  • 签名:function deflationWhitelist(address account) external view returns (bool)
  • 权限:ANYONE
  • 用途:查询指定账户是否在通缩白名单中(白名单余额不衰减)。

6. Ownable 标准函数

合约使用 OpenZeppelin Ownable,提供以下标准接口(节选):

函数 签名 说明
owner function owner() external view returns (address) 当前合约所有者
transferOwnership function transferOwnership(address newOwner) external 发起所有权转移(仅 owner)
renounceOwnership function renounceOwnership() external 放弃所有权(仅 owner)

7. 事件索引

事件 签名 触发时机
LiquidityPairUpdated event LiquidityPairUpdated(address indexed previousPair, address indexed newPair) Pair 地址更新
LpDividendAddressUpdated event LpDividendAddressUpdated(address indexed previousAddress, address indexed newAddress) LP 分发地址更新
EcoFundAddressUpdated event EcoFundAddressUpdated(address indexed newAddress) 生态基金地址更新
RouterUpdated event RouterUpdated(address indexed previousRouter, address indexed newRouter) 路由地址更新
UsdtUpdated event UsdtUpdated(address indexed previousUsdt, address indexed newUsdt) USDT 地址更新
TaxWhitelistUpdated event TaxWhitelistUpdated(address indexed account, bool whitelisted) 买卖税白名单变更
DeflationWhitelistUpdated event DeflationWhitelistUpdated(address indexed account, bool whitelisted) 通缩白名单变更
TaxDistributed event TaxDistributed(uint256 burnAmount, uint256 swapAmount, uint256 usdtReceived) 税费分配完成(每次成功执行 _doDistribution 时触发)
Transfer event Transfer(address indexed from, address indexed to, uint256 value) 转账(来自 OZ ERC20)
Approval event Approval(address indexed owner, address indexed spender, uint256 value) 授权(来自 OZ ERC20)

8. 错误索引

错误 触发条件
ZeroAddress() 关键参数为零地址(适用于 setLpDividendAddress / setEcoFundAddress / setUsdt / addToWhitelist 等)
ZeroUsdtAddress() 构造函数中 usdt_ 为零地址
ZeroRouterAddress() 构造函数中或 setRouternewRouter 为零地址
LiquidityPairNotSet() 发生买卖时 liquidityPair == 0
LpDividendAddressNotSet() 发生买卖时 lpDividendAddress == 0
InsufficientBalance(have, want) 非白名单账户的通缩后余额不足
InsufficientOzBalance(have, want) 白名单账户的 OZ 原生余额不足
OnlySelf() 内部 _doDistribution 被以 address(this) 之外的身份直接调用

9. 通缩模型示例

合约采用复利通缩:每天对当前余额减少 5%,N 天后余额为 baseBalance * 0.95^N。每一天内部又按 288 个 5 分钟周期线性分布。

假设 Alice 的基线余额 baseBalance = 1000 GOAT27,已 5 天未动:

时间(UTC) 累计天数 当前余额(估算)
T0 0 1000.00
T0 + 1 day 1 950.00
T0 + 2 day 2 902.50
T0 + 5 day 5 773.78
2027-02-05 16:00 UTC 后 冻结 不再衰减(按 2027-02-05 16:00 UTC 时刻余额锁定)

注意:即使超过 deflationStopTime,所有非白名单账户的余额仍会持续更新,但衰减上限被钉死在 2027-02-05 16:00 UTC 时刻的余额;之后任何转账、查询都会使用这个冻结值。


10. 税费分配流程

每次 accumulatedTax >= TAX_THRESHOLD (10000 * 1e18) 触发一次自动分配,或在阈值未达时任何人可手动调用 triggerDistribution()。单次分配流程:

1
2
3
4
5
accumulatedTax(假设 X) 
→ 销毁 X * 20% → 黑洞地址
→ 兑换 X * 80% → USDT(走 PancakeSwap)
→ USDTReceived * 50% → lpDividendAddress(同时调用其 triggerDistribution)
→ USDTReceived * 50% → ecoFundAddress

原子性:USDT 转账与 lpDividendAddress.triggerDistribution 必须在同一交易中全部成功;任一失败会导致整个 _doDistribution 回退(USDT 转账、burnAmount 销毁、accumulatedTax 清零均撤销)。


11. 买/卖自动税流程

from == liquidityPair 时判定为买入;to == liquidityPair 时判定为卖出。两者均不在白名单时:

1
2
3
4
5
6
7
用户发起 transfer/transferFrom
→ _update 检查 from/to
→ 若 from 或 to 在 taxWhitelist → 走无税路径
→ 否则 effectiveValue = value,taxAmount = effectiveValue * 5%
→ netAmount 转给 to
→ taxAmount 累加到 accumulatedTax
→ 若 accumulatedTax >= 10000e18 → 触发自动分配(下一笔 _update 或下一次交易)

注意:自动分配走 try/catch,即使分配失败也不会影响本次转账;但 triggerDistribution() 直接调用时失败会回退调用者整个交易。