CertiK reviewed Zebec (Zebec - Rust) on 30 Mar 2024: 9 findings, 0 critical; 7 marked fixed, 1 acknowledged, 1 open.
Report hosted on skynet.certik.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 1 | 0 |
| Medium | 0 | 0 | 1 |
| Low | 1 | 0 | 6 |
Based on the code logic below, it's clear that the value of the `amount` argument provided is used for both burning `ZBC` and minting `ZBCN`. Notably, there is no code logic for decimal conversion. Consequently, the minted amount of `ZBCN` does not match the expected value. **[migrate_token.rs#L97](https://github.com/Zebec-protocol/migration-program/blob/938b8d6e58860f210ac1110ce6850399329e68ba/programs/migration-program/src/instructions/migrate_token.rs#L97)** ```rust=97 // Burn ZBC tokens. burn(burn_ctx, amount)?; ``` **[migrate_token.rs#L114](https://github.com/Zebec-protocol/migration-program/blob/938b8d6e58860f210ac1110ce6850399329e68ba/programs/migration-program/src/instructions/migrate_token.rs#L114)** ```rust=114 // Mint equivalent ZBCN tokens that were burned. mint_to(mint_ctx, amount)?; ```
Based on the code logic below, it's evident that the provided `amount` argument value is used for both burning `ZBC` and minting `ZBCN`. This implies that the conversion rate between `ZBC` and `ZBCN` tokens is 1:1 when they have the same decimal precision. **[migrate_token.rs#L97](https://github.com/Zebec-protocol/migration-program/blob/938b8d6e58860f210ac1110ce6850399329e68ba/programs/migration-program/src/instructions/migrate_token.rs#L97)** ```rust=97 // Burn ZBC tokens. burn(burn_ctx, amount)?; ``` **[migrate_token.rs#L114](https://github.com/Zebec-protocol/migration-program/blob/938b8d6e58860f210ac1110ce6850399329e68ba/programs/migration-program/src/instructions/migrate_token.rs#L114)** ```rust=114 // Mint equivalent ZBCN tokens that were burned. mint_to(mint_ctx, amount)?; ``` The holders of `ZBC` token assets accesses the `migrate_token()` function to convert a specified amount, rather than their entire holding, of `ZBC` to `ZBCN`. Therefore, the duration of the token migration is not predetermined. Throughout the migration process, the prices of `ZBC` and `ZBCN` may differ. In such instances, a 1:1 amount conversion could potentially reduce the value of the holder's assets if the price of `ZBCN` is lower than that of `ZBC`. **[lib.rs#L21](https://github.com/Zebec-protocol/migration-program/blob/938b8d6e58860f210ac1110ce6850399329e68ba/programs/migration-program/src/lib.rs#L21)** ```rust=21 pub fn migrate_token(ctx: Context<MigrateToken>, amount: u64) -> Result<()> { migrate_token::handler(ctx, amount) } ```
According to the logic outlined in the following code, it is evident that only 10 billion `ZBCN` tokens are minted via the `migration-program`, implying that only 10 billion `ZBC` tokens undergo migration. **[migrate_token.rs#L84](https://github.com/Zebec-protocol/migration-program/blob/938b8d6e58860f210ac1110ce6850399329e68ba/programs/migration-program/src/instructions/migrate_token.rs#L84)** ```rust=84 // The migration program is one way ZBC -> ZBCN. The migration program will stop once 10,000,000,000 ZBCN tokens are minted. require!( migrate_pda.total_migrated + amount <= 10_000_000_000 * 10u64.pow(zbcn_decimals as u32), MigrationError::MaxMigrationReached ); ```
According to the comment at L27, the `mint_authority` account has been designated the mint authority role for the `ZBCN` token. However, the current codebase lacks the necessary logic to assign the mint authority role for the `ZBCN` token to the `mint_authority` account. ```rust=19 #[account( init, payer = admin, space = 8, seeds = [b"zbcn_mint"], bump )] /// CHECK: seeds has been checked /// This account has mint authority for ZBCN tokens. pub mint_authority: AccountInfo<'info>, /// ZBC (new) mint account. pub zbc_mint: Account<'info, Mint>, /// ZBCN (old) mint account. pub zbcn_mint: Account<'info, Mint>, ```
The following `CPI` is utilized for minting `ZBCN`, however, the variable name `mint_zbc` fails to accurately convey the meaning of `MintTo` struct instance. ```rust=103 let mint_zbc = MintTo { mint: zbcn_mint.to_account_info(), to: sender_zbcn_ata.to_account_info(), authority: mint_authority.to_account_info(), }; let mint_ctx = CpiContext::new_with_signer( token_program.to_account_info(), mint_zbc, mint_authority_seed, ); ```
Based on the comment at L27, the `mint_authority` account has been assigned the role of mint authority for the `ZBCN` token. However, a current flaw in the code is the lack of a check to verify whether the `zbcn_mint` mint authority truly corresponds to the `mint_authority` PDA. And after executing `init_config()` instruction, `migrate_pda.zbcn_mint` and `migrate_pda.mint_authority` cannot be updated. **[init_config.rs#L19](https://github.com/Zebec-protocol/migration-program/blob/938b8d6e58860f210ac1110ce6850399329e68ba/programs/migration-program/src/instructions/init_config.rs#L19)** ```rust=19 #[account( init, payer = admin, space = 8, seeds = [b"zbcn_mint"], bump )] /// CHECK: seeds has been checked /// This account has mint authority for ZBCN tokens. pub mint_authority: AccountInfo<'info>, /// ZBC (new) mint account. pub zbc_mint: Account<'info, Mint>, /// ZBCN (old) mint account. pub zbcn_mint: Account<'info, Mint>, ``` A similar issue also exists in `migrate_token.rs`. **[migrate_token.rs#L39](https://github.com/Zebec-protocol/migration-program/blob/938b8d6e58860f210ac1110ce6850399329e68ba/programs/migration-program/src/instructions/migrate_token.rs#L39)** ```rust=39 /// ZBCN (new) mint account. pub zbcn_mint: Account<'info, Mint>, #[account( mut, seeds = [b"zbcn_mint"], bump )] /// CHECK: seeds has been checked /// This account has mint authority for ZBCN tokens. pub mint_authority: AccountInfo<'info>, ```
The space constraint at L13 serves to restrict the on-chain storage size of `migrate_pad`. In general, the `#[derive(InitSpace)]` macro is used to record `Migrate` storage size through adding an `INIT_SPACE` constant. This constant's value equals the sum of the sizes of the struct's fields with fixed byte sizes. However, the usage of the `std::mem::size_of::<Migrate>()` function will get the size for the `Migrate` struct, including padding, exceeds the value of the `INIT_SPACE` constant. Consequently, the on-chain storage size of `migrate_pad` becomes larger than necessary, and will pay more rent lamports than actually needed. **[init_config.rs#L10](https://github.com/Zebec-protocol/migration-program/blob/938b8d6e58860f210ac1110ce6850399329e68ba/programs/migration-program/src/instructions/init_config.rs#L10)** ```rust=10 #[account( init, payer = admin, space = 8 + std::mem::size_of::<Migrate>(), seeds = [b"migrate"], bump )] /// PDA that stores the migration state and authority. pub migrate_pda: Box<Account<'info, Migrate>>, ```
The report names a repository or files. Open the report to see its scope.
1,044 projects reviewed · 1,375 reports · latest May 2025
See CertiK’s auditsSomething wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us