README
Solidity Doppelgaenger
🌐 npm install solidity-doppelganger
A tool to check if a contract is similar to a set of known/common contracts stored in a DB. E.g. quickly check if a contract SafeMath
was copied from a reputable source without having to manually check it.
Allows for strict/exact
and fuzzy
AST based Doppelgänger detection.
Example
Setup
// Import
const { SolidityDoppelganger, HASH_MODES } = require('./SolidityDoppelganger');
Input is Solidity SourceCode
// Import:
const fs = require("fs");
fs.readFile(fpath, (err, data) => {
if (err) {
console.error(`ERROR processing file '${fpath}': ${err}`);
return;
}
let selectedModes = Array(...new Set(options.modes.split(',').filter(m => HASH_MODES.includes(m))));
let dupeFinder = new SolidityDoppelganger({ modes: selectedModes });
/**
* Optionally hash inputs and print them
* */
dupeFinder.hashSourceCode(data.toString('utf-8'))
.then(results =>
results.forEach(r =>
r.then(x => {
// Result Object
let result = {
name: x.name,
hash: x.hash,
options: x.options,
path: `${fpath}`
};
console.log(JSON.stringify(result));
})
)
);
/**
* Compare sourceCode with database
* */
dupeFinder.compareSourceCode(data.toString('utf-8'), fpath)
.then(results => {
Object.keys(results.results).forEach(contractName => {
// results per contract and path
let resultobj = results.results[contractName];
console.log(`**** MATCH ****: ${resultobj.target.path} :: ${resultobj.target.name}`);
for (let m of resultobj.matches) {
console.log(` :: ${m.name} :: ${m.path} (mode=${m.options.mode})`);
}
});
});
});
Input is Contract AST
/*
print codehashes
*/
if (options.print) {
dupeFinder.hashSourceCode(data.toString('utf-8'))
.then(results => {
results.forEach(x => {
let result = {
name: x.name,
hash: x.hash,
options: x.options,
path: `${options.basePath}${fpath}`
};
console.log(JSON.stringify(result));
});
});
}
/*
find similar contracts
*/
if (options.compare) {
dupeFinder.compareSourceCode(data.toString('utf-8'), fpath)
.then(results => {
Object.keys(results.results).forEach(contractName => {
let resultobj = results.results[contractName];
console.log(`**** MATCH ****: ${resultobj.target.path} :: ${resultobj.target.name}`);
for (let m of resultobj.matches) {
console.log(` :: ${m.name} :: ${m.path} (mode=${m.options.mode})`);
}
});
});
}