Compare commits
No commits in common. "main" and "master" have entirely different histories.
|
@ -1,2 +1,2 @@
|
||||||
node_modules
|
node_modules
|
||||||
config.json
|
src/config.json
|
39
README.md
39
README.md
|
@ -1,41 +1,4 @@
|
||||||
# start
|
# start
|
||||||
```
|
```
|
||||||
npm install
|
npm run start --${port} // default: 12345
|
||||||
npm run start ${port} // default: 12345
|
|
||||||
```
|
|
||||||
|
|
||||||
# api
|
|
||||||
```
|
|
||||||
1, /checkPayment/eth
|
|
||||||
[request]
|
|
||||||
method:post
|
|
||||||
params:coin string, address string, amount float64, ts uint64 (request-body)
|
|
||||||
|
|
||||||
[response]
|
|
||||||
success: {code:0, result:true, data:array[]{
|
|
||||||
"blockNumber": "23088543",
|
|
||||||
"timeStamp": "1754561951",
|
|
||||||
"hash": "0x887ba171af3ed43cec6dfaef5f0379e2718cdc91a538eea7173947461dbcfd90",
|
|
||||||
"nonce": "0",
|
|
||||||
"blockHash": "0x5752c8fc343db877853c76aa14ecdfa6aa19bc9f273e1df715cd03020395152f",
|
|
||||||
"from": "0xfdd78d01030956dc417a3057b205159490b3919e",
|
|
||||||
"contractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
|
||||||
"to": "0xa9d1e08c7793af67e9d92fe308d5697fb81d3e43",
|
|
||||||
"value": "1100000000",
|
|
||||||
"tokenName": "USDC",
|
|
||||||
"tokenSymbol": "USDC",
|
|
||||||
"tokenDecimal": "6",
|
|
||||||
"transactionIndex": "110",
|
|
||||||
"gas": "45746",
|
|
||||||
"gasPrice": "2240053599",
|
|
||||||
"gasUsed": "40348",
|
|
||||||
"cumulativeGasUsed": "16503510",
|
|
||||||
"input": "deprecated",
|
|
||||||
"methodId": "0xa9059cbb",
|
|
||||||
"functionName": "transfer(address _to, uint256 _value)",
|
|
||||||
"confirmations": "4768"
|
|
||||||
}, ... }
|
|
||||||
|
|
||||||
error: {code:-1, result:false, data: array[]} // 未转账
|
|
||||||
{code:-2, result:false, data: array[]} // coin参数不支持
|
|
||||||
```
|
```
|
4
app.js
4
app.js
|
@ -4,8 +4,6 @@ const ETH = require("./src/chain/eth")
|
||||||
const eth = new ETH()
|
const eth = new ETH()
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
app.use(express.json());
|
|
||||||
app.use(express.urlencoded({ extended: true }));
|
|
||||||
const port = process.argv[2] || 12345
|
const port = process.argv[2] || 12345
|
||||||
|
|
||||||
app.get("/", (req, res) =>{
|
app.get("/", (req, res) =>{
|
||||||
|
@ -17,7 +15,7 @@ app.post("/checkPayment/eth", async(req, res) =>{
|
||||||
let result
|
let result
|
||||||
switch (coin) {
|
switch (coin) {
|
||||||
case "eth":
|
case "eth":
|
||||||
result = await eth.checkETHPaymentStatus(address, amount, ts)
|
// 校验eth
|
||||||
break
|
break
|
||||||
case "usdt":
|
case "usdt":
|
||||||
result = await eth.checkUSDTPaymentStatus(address, amount, ts)
|
result = await eth.checkUSDTPaymentStatus(address, amount, ts)
|
||||||
|
|
151
src/chain/eth.js
151
src/chain/eth.js
|
@ -1,6 +1,6 @@
|
||||||
const app = require("../app");
|
const app = require("../app");
|
||||||
const abiDecoder = require("abi-decoder");
|
const abiDecoder = require("abi-decoder");
|
||||||
// const Web3 = require("web3");
|
const Web3 = require("web3");
|
||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
|
|
||||||
class ETH {
|
class ETH {
|
||||||
|
@ -9,7 +9,7 @@ class ETH {
|
||||||
const apiUrl = app.ethNodeUrl
|
const apiUrl = app.ethNodeUrl
|
||||||
const usdt_abi = app.abis.usdterc20_abi;
|
const usdt_abi = app.abis.usdterc20_abi;
|
||||||
const usdc_abi = app.abis.usdcerc20_abi;
|
const usdc_abi = app.abis.usdcerc20_abi;
|
||||||
// this.web3 = new Web3(new Web3.providers.HttpProvider(apiUrl));
|
this.web3 = new Web3(new Web3.providers.HttpProvider(apiUrl));
|
||||||
abiDecoder.addABI(usdt_abi);
|
abiDecoder.addABI(usdt_abi);
|
||||||
abiDecoder.addABI(usdc_abi);
|
abiDecoder.addABI(usdc_abi);
|
||||||
this.decoder = abiDecoder;
|
this.decoder = abiDecoder;
|
||||||
|
@ -25,103 +25,60 @@ class ETH {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// async decodeTxInput(txHash) {
|
async decodeTxInput(txHash) {
|
||||||
// try{
|
try{
|
||||||
// const tx = await this.web3.eth.getTransaction(txHash);
|
const tx = await this.web3.eth.getTransaction(txHash);
|
||||||
// if (!tx || !tx.input) {
|
if (!tx || !tx.input) {
|
||||||
// console.error("Transaction not found or has no input data.");
|
console.error("Transaction not found or has no input data.");
|
||||||
// return null;
|
return null;
|
||||||
// }
|
|
||||||
// return this.decodeInput(tx.input);
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("Error decoding transaction input:", error);
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// decodeUSDT(input){
|
|
||||||
// const decoded = this.decodeInput(input)
|
|
||||||
// const result = []
|
|
||||||
// if (decoded && decoded.name === "transfer") {
|
|
||||||
// for (let item of decoded.params) {
|
|
||||||
// const obj = {}
|
|
||||||
// if (item.name === "_to") {
|
|
||||||
// obj.toAddress = item.value;
|
|
||||||
// }
|
|
||||||
// if (item.name === "_value") {
|
|
||||||
// obj.amount = this.web3.utils.fromWei(item.value, "ether");
|
|
||||||
// }
|
|
||||||
// if (Object.keys(obj).length > 0) {
|
|
||||||
// result.push(obj);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// decodeUSDC(input){
|
|
||||||
// const decoded = this.decodeInput(input)
|
|
||||||
// const result = []
|
|
||||||
// if (decoded && decoded.name === "transfer") {
|
|
||||||
// for (let item of decoded.params) {
|
|
||||||
// const obj = {}
|
|
||||||
// if (item.name === "to") {
|
|
||||||
// obj.toAddress = item.value;
|
|
||||||
// }
|
|
||||||
// if (item.name === "value") {
|
|
||||||
// obj.amount = this.web3.utils.fromWei(item.value, "mwei");
|
|
||||||
// }
|
|
||||||
// if (Object.keys(obj).length > 0) {
|
|
||||||
// result.push(obj);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
|
|
||||||
async checkETHPaymentStatus(address, amount, ts) {
|
|
||||||
const url = `${app.ethNodeUrl}
|
|
||||||
?chainid=1
|
|
||||||
&module=account
|
|
||||||
&action=txlist
|
|
||||||
&address=${address}
|
|
||||||
&startblock=0
|
|
||||||
&endblock=99999999
|
|
||||||
&page=1
|
|
||||||
&offset=100
|
|
||||||
&sort=desc
|
|
||||||
&apikey=${this.#key}`
|
|
||||||
try {
|
|
||||||
const response = await axios.get(url)
|
|
||||||
const transactions = response.data.result
|
|
||||||
if (!Array.isArray(transactions) || transactions.length === 0) {
|
|
||||||
return { code: -1, result: false, data: [] };
|
|
||||||
}
|
}
|
||||||
|
return this.decodeInput(tx.input);
|
||||||
// 筛选时间戳 >= ts 的交易
|
} catch (error) {
|
||||||
const afterTimestampTxs = transactions.filter(tx => parseInt(tx.timeStamp) >= ts);
|
console.error("Error decoding transaction input:", error);
|
||||||
|
return null;
|
||||||
if (afterTimestampTxs.length === 0) {
|
|
||||||
return { code: -1, result: false, data: [] };
|
|
||||||
}
|
|
||||||
|
|
||||||
// 筛选出金额等于指定值的交易(ETH 最小单位是 18 位)
|
|
||||||
const matchedTxs = afterTimestampTxs.filter(tx => parseFloat(tx.value) / 10 ** 18 === amount && address === tx.to);
|
|
||||||
if (matchedTxs.length === 0) {
|
|
||||||
return { code: -1, result: false, data: [] };
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
code: 0,
|
|
||||||
result: true,
|
|
||||||
data: matchedTxs.length === 1 ? matchedTxs[0] : matchedTxs,
|
|
||||||
};
|
|
||||||
} catch (error){
|
|
||||||
console.error("Error fetching transactions:", error);
|
|
||||||
return {code:-1, result: false, data:[]};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
decodeUSDT(input){
|
||||||
|
const decoded = this.decodeInput(input)
|
||||||
|
const result = []
|
||||||
|
if (decoded && decoded.name === "transfer") {
|
||||||
|
for (let item of decoded.params) {
|
||||||
|
const obj = {}
|
||||||
|
if (item.name === "_to") {
|
||||||
|
obj.toAddress = item.value;
|
||||||
|
}
|
||||||
|
if (item.name === "_value") {
|
||||||
|
obj.amount = this.web3.utils.fromWei(item.value, "ether");
|
||||||
|
}
|
||||||
|
if (Object.keys(obj).length > 0) {
|
||||||
|
result.push(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeUSDC(input){
|
||||||
|
const decoded = this.decodeInput(input)
|
||||||
|
const result = []
|
||||||
|
if (decoded && decoded.name === "transfer") {
|
||||||
|
for (let item of decoded.params) {
|
||||||
|
const obj = {}
|
||||||
|
if (item.name === "to") {
|
||||||
|
obj.toAddress = item.value;
|
||||||
|
}
|
||||||
|
if (item.name === "value") {
|
||||||
|
obj.amount = this.web3.utils.fromWei(item.value, "mwei");
|
||||||
|
}
|
||||||
|
if (Object.keys(obj).length > 0) {
|
||||||
|
result.push(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
async checkUSDTPaymentStatus(address, amount, ts){
|
async checkUSDTPaymentStatus(address, amount, ts){
|
||||||
const url = `${app.ethNodeUrl}
|
const url = `${app.ethNodeUrl}
|
||||||
?chainid=1
|
?chainid=1
|
||||||
|
@ -151,7 +108,7 @@ class ETH {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 筛选出金额等于指定值的交易(USDT 最小单位是 6 位)
|
// 筛选出金额等于指定值的交易(USDT 最小单位是 6 位)
|
||||||
const matchedTxs = afterTimestampTxs.filter(tx => parseFloat(tx.value) / 1_000_000 === amount && tx.functionName === "transfer(address _to, uint256 _value)" && address === tx.to);
|
const matchedTxs = afterTimestampTxs.filter(tx => parseFloat(tx.value) / 1_000_000 === amount && tx.functionName === "transfer(address _to, uint256 _value)");
|
||||||
|
|
||||||
if (matchedTxs.length === 0) {
|
if (matchedTxs.length === 0) {
|
||||||
return { code: -1, result: false, data: [] };
|
return { code: -1, result: false, data: [] };
|
||||||
|
@ -197,7 +154,7 @@ class ETH {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 筛选出金额等于指定值的交易(USDT 最小单位是 6 位)
|
// 筛选出金额等于指定值的交易(USDT 最小单位是 6 位)
|
||||||
const matchedTxs = afterTimestampTxs.filter(tx => parseFloat(tx.value) / 1_000_000 === amount && tx.functionName === "transfer(address _to, uint256 _value)" && address === tx.to);
|
const matchedTxs = afterTimestampTxs.filter(tx => parseFloat(tx.value) / 1_000_000 === amount && tx.functionName === "transfer(address _to, uint256 _value)");
|
||||||
|
|
||||||
if (matchedTxs.length === 0) {
|
if (matchedTxs.length === 0) {
|
||||||
return { code: -1, result: false, data: [] };
|
return { code: -1, result: false, data: [] };
|
||||||
|
|
Loading…
Reference in New Issue