Manifesto do Relatório
| Item | Descrição |
|---|---|
| Cliente | Magpie XYZ |
| Alvo | Contratos CakePie |
Histórico de Versões
| Versão | Data | Descrição |
|---|---|---|
| 1.0 | 30 de novembro de 2023 | Primeiro Lançamento |
1. Introdução
1.1 Sobre os Contratos Alvo
| Informação | Descrição |
|---|---|
| Tipo | Contrato Inteligente |
| Linguagem | Solidity |
| Abordagem | Verificação semi-automática e manual |
O alvo desta auditoria é o repositório de código dos Contratos CakePie^1 da Magpie XYZ. Os Contratos CakePie executam uma campanha CakeRush na qual os usuários podem converter seus tokens CAKE ou posição de CAKE bloqueado do PancakeSwap no CakePie. Observe que apenas CakeRush.sol e PancakeStakingBNBChain.sol estão incluídos no escopo da auditoria, enquanto outros arquivos estão fora do escopo desta auditoria.
O processo de auditoria é iterativo. Especificamente, auditaríamos os commits que corrigem os problemas descobertos. Se houver novos problemas, continuaremos esse processo. Os valores de SHA dos commits durante a auditoria são mostrados na tabela a seguir. Nosso relatório de auditoria é responsável pelo código na versão inicial (Versão 1), bem como pelo novo código (nas versões seguintes) para corrigir os problemas no relatório de auditoria.

1.2 Modelo de Segurança
Para avaliar o risco, seguimos os padrões ou sugestões amplamente adotados tanto pela indústria quanto pela academia, incluindo a Metodologia de Classificação de Risco OWASP ^2 e a Enumeração de Fraquezas Comuns ^3. A severidade geral do risco é determinada pela probabilidade e pelo impacto. Especificamente, a probabilidade é usada para estimar a chance de uma vulnerabilidade específica ser descoberta e explorada por um atacante, enquanto o impacto é usado para medir as consequências de uma exploração bem-sucedida.
Neste relatório, tanto a probabilidade quanto o impacto são categorizados em duas classificações, ou seja, alto e baixo, respectivamente, e suas combinações são mostradas na Tabela 1.1.

Dessa forma, a severidade medida neste relatório é classificada em três categorias: Alto, Médio, Baixo. Para fins de completude, Indeterminado também é utilizado para cobrir circunstâncias em que o risco não pode ser bem determinado.
Além disso, o status de um item descoberto se enquadrará em uma das seguintes quatro categorias:
-
Indeterminado Ainda sem resposta.
-
Reconhecido O item foi recebido pelo cliente, mas ainda não confirmado.
-
Confirmado O item foi reconhecido pelo cliente, mas ainda não corrigido.
-
Corrigido O item foi confirmado e corrigido pelo cliente.
2. Descobertas
No total, encontramos dois problemas potenciais. Além disso, também temos três recomendações e uma observação.
-
Risco Alto: 1
-
Risco Baixo: 1
-
Recomendação: 3
-
Observação: 1
| ID | Severidade | Descrição | Categoria | Status |
|---|---|---|---|---|
| 1 | Baixo | Estado potencialmente inconsistente após redefinição de parâmetros | Segurança de Software | Corrigido |
| 2 | Alto | Reivindicação repetida de recompensas mCake | Segurança de Software | Corrigido |
| 3 | - | Verificar os parâmetros nas funções de inicialização | Recomendação | Reconhecido |
| 4 | - | Verificar os parâmetros nos contratos CakeRush | Recomendação | Corrigido |
| 5 | - | Condições extras em modificadores | Recomendação | Reconhecido |
| 6 | - | Risco potencial de centralização | Observação | - |
Os detalhes são fornecidos nas seções a seguir.
2.1 Segurança de Software
2.1.1 Estado potencialmente inconsistente após redefinição de parâmetros
| Item | Descrição |
|---|---|
| Severidade | Baixo |
| Status | Corrigido na Versão 2 |
| Introduzido por | Versão 1 |
Descrição O contrato CakeRush distribui recompensas de acordo com vários parâmetros. As seguintes funções permitem que o mantenedor do projeto redefina alguns dos parâmetros:
function resetMultiplier() external onlyOwner {
uint256 len = rewardMultiplier.length;
for (uint8 i = 0; i < len; ++i) {
rewardMultiplier.pop();
rewardTier.pop();
}
tierLength = 0;
}
function resetTimeWeighting() external onlyOwner {
uint256 len = weightedTime.length;
for (uint8 i = 0; i < len; ++i) {
weightedTime.pop();
weighting.pop();
}
weightLength = 0;
}
Listagem 2.1: CakeRush.sol
No entanto, essas funções apenas redefinem os parâmetros, mas não as informações do usuário armazenadas na variável de estado userInfos. Como resultado, os cálculos no contrato CakeRush podem falhar devido ao estado inconsistente. Por exemplo, se os parâmetros forem redefinidos e configurados com valores incorretos, a subtração na Linha 155 pode falhar devido a underflow de inteiro.
function quoteConvert(
uint256 _amountToConvert,
address _account
)
external
view
returns (
uint256 newUserFactor,
uint256 newTotalFactor,
uint256 newUserWeightedFactor,
uint256 newWeightedTotalFactor
)
{
if (_amountToConvert == 0 || rewardMultiplier.length == 0 || weighting.length == 0)
return (0, 0, 0, 0);
UserInfo storage userInfo = userInfos[_account];
uint256 accumulated = _amountToConvert + userInfo.converted;
uint256 factorAccuNoWeighting = 0;
uint256 i = 1;
while (i < rewardTier.length && accumulated > rewardTier[i]) {
factorAccuNoWeighting += (rewardTier[i] - rewardTier[i - 1]) * rewardMultiplier[i - 1];
i++;
}
factorAccuNoWeighting += (accumulated - rewardTier[i - 1]) * rewardMultiplier[i - 1];
uint256 factorToEarnNoWeighting = (factorAccuNoWeighting / DENOMINATOR) - userInfo.factor;
Listagem 2.2: CakeRush.sol
Pior ainda, se os usuários chamarem convert ou convertWithCakePool imediatamente após a redefinição dos parâmetros (antes que os novos parâmetros sejam definidos, por exemplo, por meio de back-running) isso pode levar à redefinição dos fatores totais e ponderados registrados dentro do contrato, devido à lógica nas Linhas 141-142.
Impacto A redefinição de parâmetros pode levar a um estado inconsistente e incorreto.
Sugestão Definir os novos parâmetros após limpar os antigos.
Resposta do Projeto Os multiplicadores não serão redefinidos depois que a campanha cake rush for iniciada.
2.1.2 Reivindicação repetida de recompensas mCake
| Item | Descrição |
|---|---|
| Severidade | Alto |
| Status | Corrigido na Versão 3 |
| Introduzido por | Versão 2 |
Descrição Após bloquear tokens CAKE no contrato, os usuários podem reivindicar tokens mCake como recompensas por meio da função. No entanto, a função contém um problema que permite aos usuários reivindicar as recompensas várias vezes. No seguinte segmento de código, se o valor for maior que o do usuário, seria transferido ou depositado um valor total para o usuário. A implementação correta deveria retornar apenas, portanto a implementação atual efetivamente permite que um usuário reivindique repetidamente as recompensas mCake.
function claim(bool _isStake) external nonReentrant {
UserInfo storage userInfo = userInfos[msg.sender];
if (claimedMCake[msg.sender] >= userInfo.converted) revert AlreadyClaimed();
if (_isStake && userInfo.converted > 0) {
if (masterCakepie == address(0)) revert MasterCakepieNotSet();
IERC20(mCakeOFT).safeApprove(address(masterCakepie), userInfo.converted);
IMasterCakepie(masterCakepie).depositFor(
address(mCakeOFT),
address(msg.sender),
userInfo.converted
);
} else if (userInfo.converted > 0) {
IERC20(mCakeOFT).transfer(msg.sender, userInfo.converted);
emit Claim(msg.sender, userInfo.converted);
}
claimedMCake[msg.sender] = userInfo.converted;
}
Listagem 2.3: CakeRush.sol
Impacto Os usuários são capazes de reivindicar recompensas mCake repetidamente.
Sugestão Revisar a lógica de reivindicação de recompensas.
2.2 Recomendação Adicional
2.2.1 Verificar os parâmetros nas funções de inicialização
| Item | Descrição |
|---|---|
| Status | Reconhecido |
| Introduzido por | Versão 1 |
Descrição Nas funções de inicialização dos contratos CakeRush e PancakeStakingBNBChain, há parâmetros que não podem ser alterados após a inicialização. Recomenda-se que esses parâmetros sejam verificados nas funções de inicialização.
function __CakeRush_init(
address _cake,
address _mCakeOFT,
address _masterCakepie
) public initializer {
__Ownable_init();
__ReentrancyGuard_init();
__Pausable_init();
cake = _cake;
mCakeOFT = _mCakeOFT;
masterCakepie = _masterCakepie;
}
Listagem 2.4: CakeRush.sol
Impacto N/A
Sugestão Verificar os parâmetros nas funções de inicialização.
2.2.2 Verificar os parâmetros nos contratos CakeRush
| Item | Descrição |
|---|---|
| Status | Corrigido na Versão 2 |
| Introduzido por | Versão 1 |
Descrição No contrato CakeRush, vários parâmetros relacionados à distribuição de recompensas podem ser adicionados. No entanto, não há verificação de que esses parâmetros estejam definidos corretamente de acordo com as suposições no contrato. Especificamente, nas funções setMultipler e setTimeWeighting, condições extras devem ser verificadas (ou seja, a propriedade de aumento monotônico dos arrays rewardTier e weightedTime).
function setMultiplier(
uint256[] calldata _multiplier,
uint256[] calldata _tier
) external onlyOwner {
if (_multiplier.length == 0 || (_multiplier.length != _tier.length)) revert LengthInvalid();
for (uint8 i = 0; i < _multiplier.length; ++i) {
if (_multiplier[i] == 0) revert InvalidAmount();
rewardMultiplier.push(_multiplier[i]);
rewardTier.push(_tier[i]);
tierLength += 1;
}
}
Listagem 2.5: CakeRush.sol
Impacto N/A
Sugestão Verificar os parâmetros nas funções que os definem.
2.2.3 Condições extras em modificadores
| Item | Descrição |
|---|---|
| Status | Reconhecido |
| Introduzido por | Versão 1 |
Descrição No contrato CakeRush, o modificador _onlyPancakeStaking possui uma condição estranha. De acordo com a semântica deste modificador, verificar msg.sender != pancakeStaking seria suficiente.
modifier _onlyPancakeStaking() {
if (pancakeStaking == address(0) || msg.sender != pancakeStaking)
revert OnlyPancakeStaking();
_;
}
Listagem 2.6: CakeRush.sol
Impacto N/A
Sugestão Remover condições desnecessárias no modificador.
2.3 Observação
2.3.1 Risco potencial de centralização
Descrição O proprietário do CakeRush detém privilégios significativos para modificar configurações críticas. Isso cria um ponto único de falha. Se um atacante comprometer o proprietário, ele poderia potencialmente incapacitar todo o sistema.
Além disso, os tokens CAKE no contrato não são explicitamente tratados para serem bloqueados no contrato VECake. Em vez disso, o CakeRush permite que o proprietário retire todos esses CAKEs, o que significa que o proprietário deve bloquear os tokens CAKE após o saque. No entanto, a lógica não é garantida no nível do código, o que também traz preocupações de centralização.
Resposta do Projeto A equipe tornará o proprietário um multisig para mitigar o risco.
3. Avisos e Observações
3.1 Isenção de Responsabilidade
Este relatório de auditoria não constitui aconselhamento de investimento ou recomendação pessoal. Ele não considera, e não deve ser interpretado como considerando ou tendo qualquer influência sobre, a economia potencial de um token, venda de token ou qualquer outro produto, serviço ou outro ativo. Nenhuma entidade deve se basear neste relatório de nenhuma forma, inclusive para fins de tomar quaisquer decisões de compra ou venda de qualquer token, produto, serviço ou outro ativo.
Este relatório de auditoria não é um endosso de nenhum projeto ou equipe específica, e o relatório não garante a segurança de nenhum projeto específico. Esta auditoria não oferece nenhuma garantia quanto à descoberta de todos os problemas de segurança dos contratos inteligentes, ou seja, o resultado da avaliação não garante a inexistência de quaisquer outras descobertas de problemas de segurança. Como uma auditoria não pode ser considerada abrangente, sempre recomendamos prosseguir com auditorias independentes e um programa público de recompensas por bugs para garantir a segurança dos contratos inteligentes.
O escopo desta auditoria está limitado ao código mencionado na Seção 1.1. A menos que explicitamente especificado, a segurança da própria linguagem (por exemplo, a linguagem Solidity), a cadeia de ferramentas de compilação subjacente e a infraestrutura de computação estão fora do escopo.
3.2 Procedimento de Auditoria
Realizamos a auditoria de acordo com o seguinte procedimento.
-
Detecção de Vulnerabilidades Primeiro verificamos os contratos inteligentes com analisadores de código automáticos e, em seguida, verificamos manualmente (rejeitamos ou confirmamos) os problemas relatados por eles.
-
Análise Semântica Estudamos a lógica de negócios dos contratos inteligentes e realizamos investigações adicionais sobre as possíveis vulnerabilidades usando uma ferramenta automática de fuzzing (desenvolvida por nossa equipe de pesquisa). Também analisamos manualmente possíveis cenários de ataque com auditores independentes para verificar os resultados.
-
Recomendação Fornecemos alguns conselhos úteis aos desenvolvedores sob a perspectiva de boas práticas de programação, incluindo otimização de gas, estilo de código, entre outros.
Apresentamos os principais pontos de verificação concretos a seguir.
3.2.1 Segurança de Software
-
Reentrância
-
DoS
-
Controle de acesso
-
Tratamento e fluxo de dados
-
Tratamento de exceções
-
Chamada externa não confiável e fluxo de controle
-
Consistência de inicialização
-
Operação de eventos
-
Aleatoriedade propensa a erros
-
Uso inadequado do sistema de proxy
3.2.2 Segurança DeFi
-
Consistência semântica
-
Consistência de funcionalidade
-
Gerenciamento de permissões
-
Lógica de negócios
-
Operação de tokens
-
Mecanismo de emergência
-
Segurança de oracle
-
Lista branca e lista negra
-
Impacto econômico
-
Transferência em lote
3.2.3 Segurança NFT
-
Item duplicado
-
Verificação do receptor do token
-
Segurança de metadados fora da cadeia
3.2.4 Recomendação Adicional
-
Otimização de gas
-
Qualidade e estilo de código
Observação Os pontos de verificação anteriores são os principais. Podemos utilizar mais pontos de verificação durante o processo de auditoria de acordo com a funcionalidade do projeto.



