背景
在 EVM 生態上,存在各式各樣的 ERC20 代幣,因其實現方式有著極高的自由度,也催生了花樣繁多的惡意代幣。這些惡意代幣通常會在程式碼中實現一些惡意的邏輯(禁止使用者賣出,特權鑄造或銷燬等),其目的就是騙取使用者買入後把使用者的錢捲走。
誒!為了解決這個情況,Solana 官方提供了官方的代幣模板。你要在 Solana 上發行貨幣,只需要填寫一些基本資訊,不需要編寫代幣邏輯,即可部署一個 SPL 代幣。
但是,即使是這種情況, Solana 鏈上還是存在許多惡意代幣,各自用著不同的手法來坑騙代幣持有者。所以本篇文章嘗試著分析從哪些維度可以判斷一個 SPL/SPL2022 代幣是否存在安全隱患或惡意傾向。
有關 SPL 和 SPL2022 的背景與定義,讀者可閱讀官方文件進行了解:https://spl.solana.com/token
SPL 代幣
SPL 文件:https://spl.solana.com/token
SPL 程式碼:https://github.com/solana-labs/solana-program-library/tree/master/token/program
SPL 代幣實現了 25 個指令,根據 instruction::TokenInstruction
將 SPL 代幣的指令根據功能進行分類總結:
- 初始化代幣鑄造:
InitializeMint
,InitializeMint2
- 初始化新的代幣鑄造賬戶。 - 初始化代幣賬戶:
InitializeAccount
,InitializeAccount2
,InitializeAccount3
- 初始化新的代幣持有賬戶。 - 初始化多重簽名:
InitializeMultisig
,InitializeMultisig2
- 初始化多重簽名賬戶。 - 轉賬:
Transfer
,TransferChecked
- 在賬戶之間轉移代幣。 - 授權:
Approve
,ApproveChecked
- 授權委託人使用一定數量的代幣。 - 撤銷授權:
Revoke
- 撤銷對委託人的授權。 - 設定許可權:
SetAuthority
- 更改鑄造或賬戶的許可權。 - 鑄造代幣:
MintTo
,MintToChecked
- 鑄造新代幣到指定賬戶。 - 銷燬代幣:
Burn
,BurnChecked
- 從賬戶中銷燬代幣。 - 關閉賬戶:
CloseAccount
- 關閉代幣賬戶並轉移剩餘SOL。 - 凍結/解凍賬戶:
FreezeAccount
,ThawAccount
- 凍結或解凍代幣賬戶。 - 同步原生代幣:
SyncNative
- 同步包裝的SOL賬戶餘額。 - 獲取賬戶資料大小:
GetAccountDataSize
- 獲取給定鑄造的賬戶所需大小。 - 初始化不可變所有者:
InitializeImmutableOwner
- 為賬戶初始化不可變所有者擴充套件。 - 金額轉換:
AmountToUiAmount
,UiAmountToAmount
- 在原始金額和UI顯示金額之間轉換。
當然這麼多功能不需全部,我們只需要關注其中的一些有可能為作惡提供條件的功能。
涉及到管理員許可權的特殊函式
-
InitializeMint
InitializeMint { /// Number of base 10 digits to the right of the decimal place. decimals: u8, /// The authority/multisignature to mint tokens. mint_authority: Pubkey, /// The freeze authority/multisignature of the mint. freeze_authority: COption<Pubkey>, },
引數解釋:
decimals
: 代幣的小數位數。mint_authority
: 代幣鑄造許可權的地址。freeze_authority
: 凍結代幣賬戶的地址(可選)。
-
SetAuthority
SetAuthority { /// The type of authority to update. authority_type: AuthorityType, /// The new authority new_authority: COption<Pubkey>, },
引數解釋:
authority_type
: 指定要更改的許可權型別(有 MintTokens, FreezeAccount, AccountOwner, CloseAccount 四類)。new_authority
: 新的許可權地址。如果設定為None
,則表示移除該許可權。
SPL 代幣評價維度
由於 SPL 代幣為官方 Program 統一建立,所以在程式碼層面不作檢查。
- 許可權地址設定,引數設定
freeze_authority
是否配置。如果配置凍結特權賬號,則該賬戶可以對使用者的代幣進行凍結。
- 是否行使了特權賬戶的權力
-
FreezeAccount
:是否曾經對使用者的代幣賬戶進行凍結。 -
SetAuthority
:(MintTokens, FreezeAccount, AccountOwner, CloseAccount) 許可權轉移。- Mint Program: MintTokens 許可權轉移, FreezeAccount 許可權轉移
- Token Account: AccountOwner 許可權轉移, CloseAccount 許可權轉移
Account 初始化的 CloseAccount 許可權賬戶為 None,需要賬戶 owner 先呼叫
SetAuthority
配置許可權賬戶後再呼叫CloseAccount
指令。
-
SPL 2022 代幣
SPL 文件:https://spl.solana.com/token-2022/extensions
SPL 程式碼:https://github.com/solana-labs/solana-program-library/tree/master/token/program-2022
Token-2022 中的所有新指令都從 Token 的指令後面開始新增。 Token 有 25 條獨特的指令,索引從 0 到 24。Token-2022 支援所有這些指令,然後在索引 25 處新增了新的功能。
Mint 擴充套件目前包括:
confidential transfers
保密傳輸transfer fees
轉讓費closing mint
關閉鑄幣廠interest-bearing tokens
生息代幣non-transferable tokens
不可轉讓代幣permanent delegate
永久委託transfer hook
轉賬 Hookmetadata pointer
後設資料指標metadata
後設資料
Account 擴充套件目前包括:
memo required on incoming transfers
傳入轉賬時需要備註immutable ownership
不可變的所有權default account state
預設帳戶狀態CPI guard
CPI 衛士
SPL 2022 代幣評價維度
在 SPL 代幣的基礎上,新增以下評價維度
-
許可權地址設定,引數設定
-
Transfer Fees
:Fee 的值是否在合理範圍。 -
Default Account State
:初始化的 Account 是否預設凍結狀態。如果初始化的 Account 處於凍結狀態,則無法進行代幣的轉移(出售)。 -
Immutable Owner
:使用者的 ATA 代幣賬戶的 owner 不允許轉移。
-
-
是否行使了特權賬戶的權力
-
Interest-Bearing Tokens
:是否為生息代幣(createInterestBearingMint),是否呼叫(updateRateInterestBearingMint)修改過利息引數。 -
Permanent Delegate
:許可權永久委託情況,被委託的賬戶擁有向任意賬戶鑄造代幣和銷燬任意賬戶代幣的許可權。 -
CPI Guard
:代幣是否採用了 CPI Guard 功能(createEnableCpiGuardInstruction)來防止非常規的呼叫,啟用(enableCpiGuard),禁止(disableCpiGuard)
-
-
程式碼實現是否存在惡意邏輯
Transfer Hook
:重點關注 Hook program 的業務邏輯是否存在作惡的可能。Hook program 由管理員部署與指定,在進行代幣轉移時會呼叫 Hook program,執行額外的業務邏輯。
案例分析
SPL2022 惡意代幣:https://solscan.io/token/Bz7vBYYuNuK8Y4KRTjaunFFAjzVbAiE1mFM9EGnZ8SHU
從交易的行為來看,這個代幣的作惡手段是在使用者獲得代幣後,利用特權賬戶銷燬使用者的所有代幣。
這就涉及到了 SPL2022的“永久委託”功能,該功能允許委託人“mewfbQ”在任何賬戶中鑄造或銷燬代幣。這是濫用特權的惡意行為。
可以從瀏覽器的資訊看到,Permanent Delegate 的賬戶設定為了 mewfbQ 地址,正是透過這個賬戶進行了惡意的操作。