multiversx-entry-points

MultiversX Entry Point Analyzer

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "multiversx-entry-points" with this command: npx skills add multiversx/mx-ai-skills/multiversx-mx-ai-skills-multiversx-entry-points

MultiversX Entry Point Analyzer

Identify the complete attack surface of a MultiversX smart contract by enumerating all public interaction points and classifying their risk levels. This is typically the first step in any security review.

When to Use

  • Starting a new security audit

  • Documenting contract public interface

  • Assessing access control coverage

  • Mapping data flow through the contract

  • Identifying high-risk endpoints for focused review

  1. Entry Point Identification

MultiversX Macros That Expose Functions

Macro Visibility Risk Level Description

#[endpoint]

Public write High State-changing public function

#[view]

Public read Low Read-only public function

#[payable("*")]

Accepts any token Critical Handles value transfers

#[payable("EGLD")]

Accepts EGLD only Critical Handles native currency

#[init]

Deploy only Medium Constructor (runs once)

#[upgrade]

Upgrade only Critical Migration logic

#[callback]

Internal High Async call response handler

#[only_owner]

Owner restricted Medium Admin functions

Scanning Commands

Find all endpoints

grep -n "#[endpoint" src/*.rs

Find all payable endpoints

grep -n "#[payable" src/*.rs

Find all views

grep -n "#[view" src/*.rs

Find callbacks

grep -n "#[callback" src/*.rs

Find init and upgrade

grep -n "#[init]|#[upgrade]" src/*.rs

  1. Risk Classification

Category A: Payable Endpoints (Critical Risk)

Functions receiving value require the most scrutiny.

#[payable("*")] #[endpoint] fn deposit(&self) { // MUST CHECK: // 1. Token identifier validation // 2. Amount > 0 validation // 3. Correct handling of multi-token transfers // 4. State updates before external calls

let payment = self.call_value().single_esdt();
require!(
    payment.token_identifier == self.accepted_token().get(),
    "Wrong token"
);
require!(payment.amount > 0, "Zero amount");

// Process deposit...

}

Checklist for Payable Endpoints:

  • Token ID validated against expected token(s)

  • Amount checked for minimum/maximum bounds

  • Multi-transfer handling if all_esdt_transfers() used

  • Nonce validation for NFT/SFT

  • Reentrancy protection (Checks-Effects-Interactions)

Category B: Non-Payable State-Changing Endpoints (High Risk)

Functions that modify state without payment.

#[endpoint] fn update_config(&self, new_value: BigUint) { // MUST CHECK: // 1. Who can call this? (access control) // 2. Input validation // 3. State transition validity

self.require_caller_is_admin();
require!(new_value > 0, "Invalid value");
self.config().set(new_value);

}

Checklist for State-Changing Endpoints:

  • Access control implemented and correct

  • Input validation for all parameters

  • State transitions are valid

  • Events emitted for important changes

  • No DoS vectors (unbounded loops, etc.)

Category C: View Functions (Low Risk)

Read-only functions, but still need review.

#[view(getBalance)] fn get_balance(&self, user: ManagedAddress) -> BigUint { // SHOULD CHECK: // 1. Does it actually modify state? (interior mutability) // 2. Does it leak sensitive information? // 3. Is the calculation expensive (DoS via gas)?

self.balances(&user).get()

}

Checklist for View Functions:

  • No state modification (verify no storage writes)

  • No sensitive data exposure

  • Bounded computation (no unbounded loops)

  • Block info usage appropriate (get_block_timestamp() may differ off-chain)

Category D: Init and Upgrade (Critical Risk)

Lifecycle functions with special considerations.

#[init] fn init(&self, admin: ManagedAddress) { // MUST CHECK: // 1. All required state initialized // 2. No way to re-initialize // 3. Admin/owner properly set

self.admin().set(admin);

}

#[upgrade] fn upgrade(&self) { // MUST CHECK: // 1. New storage mappers initialized // 2. Storage layout compatibility // 3. Migration logic correct }

Category E: Callbacks (High Risk)

Async call handlers with specific vulnerabilities.

#[callback] fn transfer_callback( &self, #[call_result] result: ManagedAsyncCallResult<()> ) { // MUST CHECK: // 1. Error handling (don't assume success) // 2. State reversion on failure // 3. Correct identification of original call

match result {
    ManagedAsyncCallResult::Ok(_) => {
        // Success path
    },
    ManagedAsyncCallResult::Err(_) => {
        // CRITICAL: Must handle failure!
        // Revert any state changes from original call
    }
}

}

  1. Analysis Workflow

Step 1: List All Entry Points

Create an inventory table:

EndpointTypePayableAccessStorage TouchedRisk
depositendpoint*PublicbalancesCritical
withdrawendpointNoPublicbalancesCritical
setAdminendpointNoOwneradminHigh
getBalanceviewNoPublicbalances (read)Low
initinitNoDeployadmin, configMedium

Step 2: Tag Access Control

For each endpoint, document who can call it:

// Public - anyone can call #[endpoint] fn public_function(&self) { }

// Owner only - blockchain owner #[only_owner] #[endpoint] fn owner_function(&self) { }

// Admin only - custom access control #[endpoint] fn admin_function(&self) { self.require_caller_is_admin(); }

// Whitelisted - address in set #[endpoint] fn whitelist_function(&self) { let caller = self.blockchain().get_caller(); require!(self.whitelist().contains(&caller), "Not whitelisted"); }

Step 3: Tag Value Handling

Classify how each endpoint handles value:

Tag Meaning Example

Refusable Rejects payments Default (no #[payable] )

EGLD Only Accepts EGLD #[payable("EGLD")]

Token Only Specific ESDT #[payable("TOKEN-abc123")]

Any Token Any payment #[payable("*")]

Multi-Token Multiple payments Uses all_esdt_transfers()

Step 4: Graph Data Flow

Map which storage mappers each endpoint reads/writes:

deposit() ──writes──▶ balances ──writes──▶ total_deposited ──reads───▶ accepted_token

withdraw() ──reads/writes──▶ balances ──reads────────▶ withdrawal_fee

getBalance() ──reads──▶ balances

  1. Specific Attack Vectors

Privilege Escalation

Is a sensitive endpoint accidentally public?

// VULNERABLE: Missing access control #[endpoint] fn set_admin(&self, new_admin: ManagedAddress) { self.admin().set(new_admin); // Anyone can become admin! }

// CORRECT: Protected #[only_owner] #[endpoint] fn set_admin(&self, new_admin: ManagedAddress) { self.admin().set(new_admin); }

DoS via Unbounded Growth

Can public endpoints cause unbounded storage growth?

// VULNERABLE: Public endpoint adds to unbounded set #[endpoint] fn register(&self) { let caller = self.blockchain().get_caller(); self.participants().insert(caller); // Grows forever! }

// Attack: Call register() with many addresses until // any function iterating participants() runs out of gas

Missing Payment Validation

Does a payable endpoint verify what it receives?

// VULNERABLE: Accepts any token #[payable("*")] #[endpoint] fn stake(&self) { let payment = self.call_value().single_esdt(); self.staked().update(|s| *s += payment.amount); // Fake tokens accepted! }

Callback State Assumptions

Does a callback assume the async call succeeded?

// VULNERABLE: Assumes success #[callback] fn on_transfer_complete(&self) { // This runs even if transfer FAILED! self.transfer_count().update(|c| *c += 1); }

  1. Output Template

Entry Point Analysis: [Contract Name]

Summary

  • Total Endpoints: X
  • Payable Endpoints: Y (Critical)
  • State-Changing: Z (High)
  • Views: W (Low)

Detailed Inventory

Critical Risk (Payable)

EndpointAcceptsAccessConcerns
deposit*PublicToken validation needed

High Risk (State-Changing)

EndpointAccessStorage ModifiedConcerns
withdrawPublicbalancesAmount validation

Medium Risk (Admin)

EndpointAccessStorage ModifiedConcerns
setConfigOwnerconfigPrivilege escalation if misconfigured

Low Risk (Views)

EndpointStorage ReadConcerns
getBalancebalancesNone

Access Control Matrix

EndpointPublicOwnerAdminWhitelist
depositYes---
setAdmin-Yes--

Recommended Focus Areas

  1. [Highest priority endpoint and why]
  2. [Second priority]
  3. [Third priority]

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

multiversx-clarification-expert

No summary provided by upstream source.

Repository SourceNeeds Review
General

multiversx-protocol-experts

No summary provided by upstream source.

Repository SourceNeeds Review
General

multiversx-smart-contracts

No summary provided by upstream source.

Repository SourceNeeds Review