Skip to main content

Cross File Support

Skittles supports sharing types, functions, and constants across multiple contract files. Organize your project just like you would any TypeScript application — define types in one file and import them wherever you need them.

Shared Types​

Type aliases (structs), interfaces (contract interfaces), and enums defined in one file can be used in any other contract file:

contracts/types.ts
import { address } from "skittles";

export enum VaultStatus {
Active,
Paused,
}

export type StakeInfo = {
amount: number;
timestamp: number;
account: address;
};

export interface IStaking {
getStakeInfo(account: address): StakeInfo;
}
contracts/Staking.ts
import { VaultStatus, StakeInfo } from "./types";

export class Staking {
public status: VaultStatus;

public getStakeInfo(account: address): StakeInfo {
let info: StakeInfo = {
amount: this.deposits[account],
timestamp: this.depositTimestamps[account],
account: account,
};
return info;
}
}

Imports work just like standard TypeScript. Define your shared types in one file, import them in your contracts, and Skittles handles the rest.

Shared Functions​

Functions declared at file level (outside any class) are available to all contracts:

contracts/utils.ts
function calculateFee(amount: number, bps: number): number {
return (amount * bps) / 10000;
}
contracts/Vault.ts
export class Vault {
withdraw(amount: number): void {
let fee: number = calculateFee(amount, 50);
// ...
}
}

Arrow functions work the same way:

const calculateFee = (amount: number, bps: number): number => {
return (amount * bps) / 10000;
};

Shared Constants​

Constants declared at file level can be shared across your contracts:

contracts/constants.ts
const MAX_FEE = 500;
const FEE_DENOMINATOR = 10000;
contracts/Vault.ts
export class Vault {
withdraw(amount: number): void {
let fee: number = (amount * MAX_FEE) / FEE_DENOMINATOR;
}
}

How It Works​

Skittles automatically scans all files in your contracts directory and makes shared definitions available to any contract that uses them. Only the types, enums, functions, and constants that a contract actually references are included in its generated Solidity — unused definitions are excluded to keep the compiled output lean.

External Contract Calls​

Smart contracts often need to interact with other deployed contracts. Skittles supports this through interfaces and the Contract<T>() helper.

Define an Interface​

First, define a TypeScript interface for the external contract:

contracts/IToken.ts
import { address } from "skittles";

export default interface IToken {
name: string;
totalSupply: number;
balanceOf(account: address): number;
transfer(to: address, amount: number): boolean;
}

Call the External Contract​

Use Contract<T>(address) to create a typed reference to a deployed contract:

contracts/Vault.ts
import { address, msg, Contract } from "skittles";
import IToken from "./IToken";

export class Vault {
private token: IToken;

constructor(tokenAddress: address) {
this.token = Contract<IToken>(tokenAddress);
}

public getTokenName(): string {
return this.token.name;
}

public getBalance(account: address): number {
return this.token.balanceOf(account);
}

public withdraw(to: address, amount: number): void {
this.token.transfer(to, amount);
}
}

Interface properties (like name and totalSupply) compile to view getter calls. You can access them with natural property syntax — no parentheses needed:

interface IToken {
function name() external view returns (string memory);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
}

contract Vault {
IToken internal token;

constructor(address tokenAddress) {
token = IToken(tokenAddress);
}

function getTokenName() public view virtual returns (string memory) {
return token.name();
}

function getBalance(address account) public view virtual returns (uint256) {
return token.balanceOf(account);
}

function withdraw(address to, uint256 amount) public virtual {
token.transfer(to, amount);
}
}

Interface as Function Parameter​

You can also pass contract references as function parameters:

public getBalance(token: IToken, account: address): number {
return token.balanceOf(account);
}

Cache Invalidation​

If you change shared types, functions, or constants, all contracts that use them are automatically recompiled. See Incremental Compilation for details.