Summary: Inter-contract communication allows different smart contracts to call each other, exchange data, and collaborate. This mechanism enables developers to build complex decentralized applications (DApps), as no single contract can handle all functionality on its own. Multiple contracts working together can implement richer application logic.
What Is Inter-Contract Communication?
Inter-contract communication refers to the ability of smart contracts to interact with each other through direct calls, inheritance, events (off-chain), or proxy patterns. It enables data exchange, function invocation, and coordinated workflows among multiple contracts.
How to Achieve Data Interaction and Collaboration
1. Direct Calls
A smart contract can directly call functions of another contract as long as those functions are public or external. This is similar to method calls in object-oriented programming.
Example:
// Contract A
contract ContractA {
function add(uint x, uint y) external returns (uint) {
return x + y;
}
}
// Contract B
contract ContractB {
function useAddFunction(address contractAAddress, uint x, uint y) public view returns (uint) {
ContractA a = ContractA(contractAAddress);
return a.add(x, y);
}
}
Here, ContractB calls the add function of ContractA by passing its address.
2. Inheritance
Smart contracts can inherit from other contracts to gain their functionality and state variables. This allows code reuse and reduces redundancy.
Example:
// Base contract
contract Base {
uint public baseValue;
function setValue(uint _value) public {
baseValue = _value;
}
}
// Derived contract
contract Derived is Base {
uint public derivedValue;
function setBothValues(uint _baseValue, uint _derivedValue) public {
setValue(_baseValue); // call Base contract function
this.derivedValue = _derivedValue;
}
}
Derived inherits from Base and can call the base contract’s method.
3. Event Emission (for Off-Chain Listeners)
Smart contracts cannot directly react to events on-chain. Events are off-chain logs meant for dApps, backend services, or monitoring tools to subscribe to. They provide transparency and real-time feedback for external applications.
Example:
// User registry contract
contract UserRegistry {
event UserAdded(address indexed userAddress, string userData);
function addUser(address userAddress, string memory userData) public {
emit UserAdded(userAddress, userData); // off-chain apps listen for this
}
}
External applications (web3.js, ethers.js, or The Graph) can listen to UserAdded events and then trigger on-chain interactions if needed.
4. Combining Events with Direct Calls (On-Chain Reaction)
If you want another contract to react automatically, you must use direct calls:
// User monitor contract
contract UserMonitor {
function handleUserAdded(address userAddress, string memory userData) public {
// handle user logic on-chain
}
}
// Updated User registry contract
contract UserRegistry {
event UserAdded(address indexed userAddress, string userData);
UserMonitor monitor;
constructor(address monitorAddress) {
monitor = UserMonitor(monitorAddress);
}
function addUser(address userAddress, string memory userData) public {
emit UserAdded(userAddress, userData); // for off-chain listeners
monitor.handleUserAdded(userAddress, userData); // on-chain reaction
}
}
Here, UserRegistry emits an event for off-chain monitoring and simultaneously calls UserMonitor on-chain to react immediately.
5. Proxy / Delegate Pattern
The proxy pattern allows one contract to act as an intermediary for other contracts. The proxy can manage multiple contracts’ logic and state, enabling flexible data interaction and easier upgrades.
Example:
// Delegate contract
contract Delegate {
uint public value;
function setValue(uint _value) public {
value = _value;
}
}
// Proxy contract
contract Proxy {
Delegate delegate;
constructor(address _delegateAddress) {
delegate = Delegate(_delegateAddress);
}
function setDelegateValue(uint _value) public {
delegate.setValue(_value);
}
}
The Proxy contract interacts with the Delegate contract and can act as a central point for managing multiple contracts.
Conclusion
Inter-contract communication is essential for building modular and complex smart contract systems. Developers should remember:
- On-chain communication requires direct calls, inheritance, or proxy patterns.
- Events are off-chain notifications for dApps and external services.
- Combining both approaches enables robust, maintainable, and responsive DApps.


