
Sybil Detection by XGBoost
Public blockchains are transparent, accurate, and comprehensive records of their entire history. These freely available data sets are some of the largest and cleanest in the world, and they are highly amenable to the application of machine learning. In 2024, the Ethereum blockchain has about 200 million addresses, which is the same as the count of active websites on the internet. It is a global, public, financial dataset of internet scale. Ranking, classification, personalization, co-occurren...

A Taxonomy of LayerZero Network Users Arising from Sybil Analysis
IntroductionA critical threat to the integrity of peer-to-peer networks, especially within blockchain ecosystems, is the Sybil attack. First identified by Douceur, this type of attack involves a single adversary creating multiple fake identities—known as Sybils—to undermine the network. These false identities can be leveraged to manipulate consensus mechanisms, disrupt the fair distribution of resources, or even execute double-spending attacks. Sybil attacks are prevalent across a variety of ...

Decentralized Onchain Microcredit
(Cover image credit: World Bank Flickr, used under a Creative Commons License.)An Onchain Approach to MicrocreditThe World Bank estimates that 1.4 billion people worldwide remained excluded from the global financial system, unable to open accounts, secure loans, or build credit histories. For these individuals, the barriers to economic opportunity are immense. Traditional credit scoring relies on access to formal financial data, including bank accounts, payment histories, and income documenta...
Applied scientist studying algorithmic reputation and identity.



Sybil Detection by XGBoost
Public blockchains are transparent, accurate, and comprehensive records of their entire history. These freely available data sets are some of the largest and cleanest in the world, and they are highly amenable to the application of machine learning. In 2024, the Ethereum blockchain has about 200 million addresses, which is the same as the count of active websites on the internet. It is a global, public, financial dataset of internet scale. Ranking, classification, personalization, co-occurren...

A Taxonomy of LayerZero Network Users Arising from Sybil Analysis
IntroductionA critical threat to the integrity of peer-to-peer networks, especially within blockchain ecosystems, is the Sybil attack. First identified by Douceur, this type of attack involves a single adversary creating multiple fake identities—known as Sybils—to undermine the network. These false identities can be leveraged to manipulate consensus mechanisms, disrupt the fair distribution of resources, or even execute double-spending attacks. Sybil attacks are prevalent across a variety of ...

Decentralized Onchain Microcredit
(Cover image credit: World Bank Flickr, used under a Creative Commons License.)An Onchain Approach to MicrocreditThe World Bank estimates that 1.4 billion people worldwide remained excluded from the global financial system, unable to open accounts, secure loans, or build credit histories. For these individuals, the barriers to economic opportunity are immense. Traditional credit scoring relies on access to formal financial data, including bank accounts, payment histories, and income documenta...
Applied scientist studying algorithmic reputation and identity.
Share Dialog
Share Dialog

Subscribe to Scott Onchain

Subscribe to Scott Onchain
<100 subscribers
<100 subscribers
This is a technical specification for a smart contract interface, intended for implementation by a solidity engineer. For an overview of onchain microlending targeted to a more general reader, please see the article Decentralized Onchain Microcredit.
depositFunds(uint256 amount)
Allows lenders to deposit funds into the protocol. The amount is in USDC, scaaled to 6 decimals. For example, 1,000,000 corresponds to 1 USDC, and passing 5,000,000 corresponds to 5 USDC.
previewLoanTerms
This function provides a read-only preview of the loan terms for a given borrower, principal, and repayment period before any state-changing action.
requestLoan(uint256 amount) → (uint256 loanId)
Borrowers call this to request a certain principal amount (in scaled USDC). The contract looks up their credit score to determine the interest rate, repayment period, and other terms. It returns a loanId to track this loan.
disburseLoan(uint256 loanId)
A follow-up function that actually sends the funds to the borrower. Depending on your logic, this might be part of requestLoan, or restricted so only the protocol (or an admin/oracle) can call it after validating the loan.
repayLoan(uint256 loanId, uint256 amount)
Allows the borrower to repay part or all of the outstanding amount. In practice, this needs to update on-chain state, reduce the loan balance, and call the oracle to trigger updates to the borrower’s and attesters’ personalization vectors. It would also handle the distribution of the “attester reward” portion.
recordAttestation(address borrower, uint256 weight)
Lets an attester vouch for a borrower’s creditworthiness. This is recorded on-chain and integrated with EAS. The weight is a value in the range [0, 1] scaled to 0-1000000.
updateCreditScore(address user, uint256 newScore)
Because a reputation score is too expensive to compute on-chain, it is computed off-chain and updated on-chain via an oracle or a trusted service. This function is where that oracle posts the updated score.
getCreditScore(address user) → (uint256 score)
A public/view function returning the on-chain record of someone’s credit score.
getLoan(uint256 loanId)
A public/view function that returns structured data about the loan (principal, outstanding balance, borrower address, etc.).
computeAttesterReward(uint256 loanId, address attester) → (uint256 reward)
A view function to calculate how much of the borrower’s latest repayment belongs to this attester, based on the attestation weight.
For the initial implementation, the interest rate is computed as follows:
,
where
is the borrower’s reputation score (between 0 and 1).
is the maximum reputation score among all borrowers
This is a technical specification for a smart contract interface, intended for implementation by a solidity engineer. For an overview of onchain microlending targeted to a more general reader, please see the article Decentralized Onchain Microcredit.
depositFunds(uint256 amount)
Allows lenders to deposit funds into the protocol. The amount is in USDC, scaaled to 6 decimals. For example, 1,000,000 corresponds to 1 USDC, and passing 5,000,000 corresponds to 5 USDC.
previewLoanTerms
This function provides a read-only preview of the loan terms for a given borrower, principal, and repayment period before any state-changing action.
requestLoan(uint256 amount) → (uint256 loanId)
Borrowers call this to request a certain principal amount (in scaled USDC). The contract looks up their credit score to determine the interest rate, repayment period, and other terms. It returns a loanId to track this loan.
disburseLoan(uint256 loanId)
A follow-up function that actually sends the funds to the borrower. Depending on your logic, this might be part of requestLoan, or restricted so only the protocol (or an admin/oracle) can call it after validating the loan.
repayLoan(uint256 loanId, uint256 amount)
Allows the borrower to repay part or all of the outstanding amount. In practice, this needs to update on-chain state, reduce the loan balance, and call the oracle to trigger updates to the borrower’s and attesters’ personalization vectors. It would also handle the distribution of the “attester reward” portion.
recordAttestation(address borrower, uint256 weight)
Lets an attester vouch for a borrower’s creditworthiness. This is recorded on-chain and integrated with EAS. The weight is a value in the range [0, 1] scaled to 0-1000000.
updateCreditScore(address user, uint256 newScore)
Because a reputation score is too expensive to compute on-chain, it is computed off-chain and updated on-chain via an oracle or a trusted service. This function is where that oracle posts the updated score.
getCreditScore(address user) → (uint256 score)
A public/view function returning the on-chain record of someone’s credit score.
getLoan(uint256 loanId)
A public/view function that returns structured data about the loan (principal, outstanding balance, borrower address, etc.).
computeAttesterReward(uint256 loanId, address attester) → (uint256 reward)
A view function to calculate how much of the borrower’s latest repayment belongs to this attester, based on the attestation weight.
For the initial implementation, the interest rate is computed as follows:
,
where
is the borrower’s reputation score (between 0 and 1).
is the maximum reputation score among all borrowers
is the smallest interest rate offered (for ),
is the largest interest rate offered (for ).
pragma solidity ^0.8.17;
interface IDecentralizedMicrocredit {
uint256 public rMin;
uint256 public rMax;
/**
* @notice Record an attestation of one participant's creditworthiness.
* @dev Constructor takes the min and max interest rate.
* @param _rMin, _rMax: Min and max interest rate (varies by
* reputation of borrower. Default: 5% to 20%
*/
constructor(uint256 _rMin, uint256 _rMax)
{
require(_rMin < _rMax, "rMin must be < rMax");
rMin = _rMin;
rMax = _rMax;
}
/**
* @notice Owner-only setter for interest rate range
* @dev This can update the interest rate range when needed.
* @param _rMin, _rMax: Min and max interest rate (varies by
* reputation of borrower.
*/
function setInterestRates(uint256 _rMin, uint256 _rMax) external onlyOwner {
require(_rMin < _rMax, "rMin must be < rMax");
rMin = _rMin;
rMax = _rMax;
}
/**
* @notice Deposit funds into the protocol as a lender.
* @dev Implemented as ERC20 transferFrom in USDC.
* @param amount Amount of USDC to deposit.
*/
function depositFunds(uint256 amount) external;
/**
* @notice Previews the loan terms for a potential borrower,
* duration, and principal amount.
* @dev
* - This is a `view` function and does not alter on-chain state.
* - The returned values can be used by a front end to understand
* the interest rate, repayment schedule, and other loan
* conditions before actually requesting the loan.
* @param borrower The address requesting the loan.
* @param principal The requested loan amount (6-decimal USDC).
* @param repaymentPeriod The requested repayment period (in seconds).
* @return interestRate The annualized interest rate for this loan,
* expressed in basis points
* (i.e., 100 = 1%, 250 = 2.50%, etc.).
* @return payment The estimated periodic payment amount,
* in 6-decimal USDC units, due every 30 days.
*/
function previewLoanTerms(
address borrower,
uint256 principal,
uint256 repaymentPeriod
)
external
view
returns (
uint256 interestRate,
uint256 payment
);
/**
* @notice Request a new microloan.
* @dev See the notes for the interest rate.
* @param amount The requested principal amount in USDC.
* @return loanId A unique identifier for the newly created loan.
*/
function requestLoan(uint256 amount) external returns (uint256 loanId);
/**
* @notice Disburse an approved loan to the borrower.
* @dev This function might be restricted so only the protocol
* can call it after validating the loan terms.
* @param loanId The ID of the loan being disbursed.
*/
function disburseLoan(uint256 loanId) external;
/**
* @notice Repay an existing loan (principal + interest +
* attester rewards).
* @dev Must do these:
* * track payment progress
* * update the pagerank personalization vector
* * distribute attester rewards
* * handle partial or full repayments.
* @param loanId The ID of the loan to repay.
* @param amount Amount sent for repayment (USDC).
*/
function repayLoan(uint256 loanId, uint256 amount) external;
/**
* @notice Record an attestation of one participant's creditworthiness.
* @dev Weight can be a value from 0 to 1
* (scale up, 0–1000000 for integer parameter).
* @param borrower The address of the borrower being attested to.
* @param weight
* A measure of how strongly the attester
* vouches for the borrower, scaled to 0-1e6
*/
function recordAttestation(address borrower, uint256 weight) external;
/**
* @notice Update a participant's credit score.
* @dev This should be restricted to an oracle that calculates
* reputation scores off-chain and posts them on-chain.
* @param user The address whose credit score is being updated.
* @param newScore The new credit score of the user.
*/
function updateCreditScore(address user, uint256 newScore) external;
/**
* @notice Retrieve the current credit score for a given address.
* @param user The address to look up.
* @return score The current on-chain credit score of the user
* (retrieved from an oracle).
*/
function getCreditScore(address user) external view returns (uint256 score);
/**
* @notice Fetch details of a loan, e.g. principal, interest, borrower, outstanding balance.
* @param loanId The ID of the loan to fetch.
* @return principal The original principal.
* @return outstanding The current remaining balance.
* @return borrower The address of the borrower.
* @return interestRate The interest rate scaled to 0-1000000
* @return isActive Whether the loan is still active
* (not fully repaid or defaulted).
*/
function getLoan(uint256 loanId)
external
view
returns (
uint256 principal,
uint256 outstanding,
address borrower,
uint256 interestRate,
bool isActive
);
/**
* @notice Compute the reward owed to an attester for a specific loan.
* @param loanId The ID of the loan.
* @param attester The address of the attester.
* @return reward The amount of reward owed to the attester,
* scaled by x100 (so that dollars and cents are scaled
to an integer.
*/
function computeAttesterReward(uint256 loanId, address attester)
external
view
returns (uint256 reward);
}
is the smallest interest rate offered (for ),
is the largest interest rate offered (for ).
pragma solidity ^0.8.17;
interface IDecentralizedMicrocredit {
uint256 public rMin;
uint256 public rMax;
/**
* @notice Record an attestation of one participant's creditworthiness.
* @dev Constructor takes the min and max interest rate.
* @param _rMin, _rMax: Min and max interest rate (varies by
* reputation of borrower. Default: 5% to 20%
*/
constructor(uint256 _rMin, uint256 _rMax)
{
require(_rMin < _rMax, "rMin must be < rMax");
rMin = _rMin;
rMax = _rMax;
}
/**
* @notice Owner-only setter for interest rate range
* @dev This can update the interest rate range when needed.
* @param _rMin, _rMax: Min and max interest rate (varies by
* reputation of borrower.
*/
function setInterestRates(uint256 _rMin, uint256 _rMax) external onlyOwner {
require(_rMin < _rMax, "rMin must be < rMax");
rMin = _rMin;
rMax = _rMax;
}
/**
* @notice Deposit funds into the protocol as a lender.
* @dev Implemented as ERC20 transferFrom in USDC.
* @param amount Amount of USDC to deposit.
*/
function depositFunds(uint256 amount) external;
/**
* @notice Previews the loan terms for a potential borrower,
* duration, and principal amount.
* @dev
* - This is a `view` function and does not alter on-chain state.
* - The returned values can be used by a front end to understand
* the interest rate, repayment schedule, and other loan
* conditions before actually requesting the loan.
* @param borrower The address requesting the loan.
* @param principal The requested loan amount (6-decimal USDC).
* @param repaymentPeriod The requested repayment period (in seconds).
* @return interestRate The annualized interest rate for this loan,
* expressed in basis points
* (i.e., 100 = 1%, 250 = 2.50%, etc.).
* @return payment The estimated periodic payment amount,
* in 6-decimal USDC units, due every 30 days.
*/
function previewLoanTerms(
address borrower,
uint256 principal,
uint256 repaymentPeriod
)
external
view
returns (
uint256 interestRate,
uint256 payment
);
/**
* @notice Request a new microloan.
* @dev See the notes for the interest rate.
* @param amount The requested principal amount in USDC.
* @return loanId A unique identifier for the newly created loan.
*/
function requestLoan(uint256 amount) external returns (uint256 loanId);
/**
* @notice Disburse an approved loan to the borrower.
* @dev This function might be restricted so only the protocol
* can call it after validating the loan terms.
* @param loanId The ID of the loan being disbursed.
*/
function disburseLoan(uint256 loanId) external;
/**
* @notice Repay an existing loan (principal + interest +
* attester rewards).
* @dev Must do these:
* * track payment progress
* * update the pagerank personalization vector
* * distribute attester rewards
* * handle partial or full repayments.
* @param loanId The ID of the loan to repay.
* @param amount Amount sent for repayment (USDC).
*/
function repayLoan(uint256 loanId, uint256 amount) external;
/**
* @notice Record an attestation of one participant's creditworthiness.
* @dev Weight can be a value from 0 to 1
* (scale up, 0–1000000 for integer parameter).
* @param borrower The address of the borrower being attested to.
* @param weight
* A measure of how strongly the attester
* vouches for the borrower, scaled to 0-1e6
*/
function recordAttestation(address borrower, uint256 weight) external;
/**
* @notice Update a participant's credit score.
* @dev This should be restricted to an oracle that calculates
* reputation scores off-chain and posts them on-chain.
* @param user The address whose credit score is being updated.
* @param newScore The new credit score of the user.
*/
function updateCreditScore(address user, uint256 newScore) external;
/**
* @notice Retrieve the current credit score for a given address.
* @param user The address to look up.
* @return score The current on-chain credit score of the user
* (retrieved from an oracle).
*/
function getCreditScore(address user) external view returns (uint256 score);
/**
* @notice Fetch details of a loan, e.g. principal, interest, borrower, outstanding balance.
* @param loanId The ID of the loan to fetch.
* @return principal The original principal.
* @return outstanding The current remaining balance.
* @return borrower The address of the borrower.
* @return interestRate The interest rate scaled to 0-1000000
* @return isActive Whether the loan is still active
* (not fully repaid or defaulted).
*/
function getLoan(uint256 loanId)
external
view
returns (
uint256 principal,
uint256 outstanding,
address borrower,
uint256 interestRate,
bool isActive
);
/**
* @notice Compute the reward owed to an attester for a specific loan.
* @param loanId The ID of the loan.
* @param attester The address of the attester.
* @return reward The amount of reward owed to the attester,
* scaled by x100 (so that dollars and cents are scaled
to an integer.
*/
function computeAttesterReward(uint256 loanId, address attester)
external
view
returns (uint256 reward);
}
No activity yet