kenryu42 / ethereum-nft-sales-bot Goto Github PK
View Code? Open in Web Editor NEWEthereum NFT sale events monitoring SDK with built-in Discord and Twitter notification.
License: MIT License
Ethereum NFT sale events monitoring SDK with built-in Discord and Twitter notification.
License: MIT License
Support Seaport 1.5.
'0x00000000000000adc04c56bf30ac9d3c0aaf14dc': {
name: 'opensea',
displayName: 'Opensea ๐',
contract: '0x00000000000000adc04c56bf30ac9d3c0aaf14dc',
color: 2130402,
site: 'https://opensea.io/assets/',
accountPage: 'https://opensea.io/',
iconURL:
'https://pbs.twimg.com/profile_images/1544105652330631168/ZuvjfGkT_400x400.png',
topics: [
'0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31'
]
},
lots of trading happening on SudoSwap and it would be great to support it
1.0.5
Thank you for this awesome library. This simplified so much work for collection creators.
This is somewhat a vague report, and not sure if this is a bug entirely either. When running ENFT via npm package on a local machine, everything works fine. The definition of works fine for me is: "It posts the sales to Discord".
However, when we package this up in a docker container and run on ecs on fargate, cloudwatch reports the following error:
(node:1) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 end listeners added to [FormData]. Use emitter.setMaxListeners() to increase limit
at _addListener (node:events:587:17)
at FormData.addListener (node:events:605:10)
at Stream.pipe (node:internal/streams/legacy:86:10)
at CombinedStream.pipe (/app/node_modules/combined-stream/lib/combined_stream.js:65:25)
at dispatchHttpRequest (file:///app/node_modules/axios/lib/adapters/http.js:645:12)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
(node:1) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 close listeners added to [FormData]. Use emitter.setMaxListeners() to increase limit
at _addListener (node:events:587:17)
at FormData.addListener (node:events:605:10)
at Stream.pipe (node:internal/streams/legacy:87:10)
at CombinedStream.pipe (/app/node_modules/combined-stream/lib/combined_stream.js:65:25)
at dispatchHttpRequest (file:///app/node_modules/axios/lib/adapters/http.js:645:12)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
(node:1) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added to [FormData]. Use emitter.setMaxListeners() to increase limit
at _addListener (node:events:587:17)
at FormData.prependListener (node:events:619:14)
at prependListener (node:internal/streams/legacy:100:20)
at Stream.pipe (node:internal/streams/legacy:66:3)
at CombinedStream.pipe (/app/node_modules/combined-stream/lib/combined_stream.js:65:25)
at dispatchHttpRequest (file:///app/node_modules/axios/lib/adapters/http.js:645:12)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
file:///app/node_modules/axios/lib/core/AxiosError.js:89
AxiosError.call(axiosError, error.message, code, config, request, response);
^
AxiosError: socket hang up
at AxiosError.from (file:///app/node_modules/axios/lib/core/AxiosError.js:89:14)
at RedirectableRequest.handleRequestError (file:///app/node_modules/axios/lib/adapters/http.js:577:25)
at RedirectableRequest.emit (node:events:525:35)
at eventHandlers.<computed> (/app/node_modules/follow-redirects/index.js:14:24)
at ClientRequest.emit (node:events:513:28)
at TLSSocket.socketOnEnd (node:_http_client:526:9)
at TLSSocket.emit (node:events:525:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'ECONNRESET',
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [ 'xhr', 'http' ],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: {
FormData: [Function: FormData] {
LINE_BREAK: '\r\n',
DEFAULT_CONTENT_TYPE: 'application/octet-stream'
},
Blob: [class Blob]
},
validateStatus: [Function: validateStatus],
headers: AxiosHeaders {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'multipart/form-data; boundary=--------------------------116409738858655009138031',
'User-Agent': 'axios/1.3.4',
'Content-Length': '336452',
'Accept-Encoding': 'gzip, compress, deflate, br'
},
method: 'post',
url: 'https://discord.com/api/webhooks/<correct webhook id>',
data: FormData {
_overheadLength: 261,
_valueLength: 336191,
_valuesToMeasure: [],
writable: false,
readable: true,
dataSize: 0,
maxDataSize: 2097152,
pauseStreams: true,
_released: true,
_streams: [],
_currentStream: null,
_insideLoop: false,
_pendingNext: false,
_boundary: '--------------------------116409738858655009138031',
_events: [Object: null prototype] {
end: [
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
warned: true
],
error: [
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
[Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
warned: true
],
close: [
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
[Function (anonymous)],
warned: true
]
},
_eventsCount: 3
}
},
request: <ref *3> Writable {
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
_events: [Object: null prototype] {
response: [Function: handleResponse],
error: [Function: handleRequestError],
socket: [Function: handleRequestSocket]
},
_eventsCount: 3,
_maxListeners: undefined,
_options: {
maxRedirects: 21,
maxBodyLength: Infinity,
protocol: 'https:',
path: '/api/webhooks/<correct webhook id>',
method: 'POST',
headers: [Object: null prototype] {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'multipart/form-data; boundary=--------------------------116409738858655009138031',
'User-Agent': 'axios/1.3.4',
'Content-Length': '336452',
'Accept-Encoding': 'gzip, compress, deflate, br'
},
agents: { http: undefined, https: undefined },
auth: undefined,
beforeRedirect: [Function: dispatchBeforeRedirect],
beforeRedirects: { proxy: [Function: beforeRedirect] },
hostname: 'discord.com',
port: '',
agent: undefined,
nativeProtocols: {
'http:': {
_connectionListener: [Function: connectionListener],
METHODS: [
'ACL', 'BIND', 'CHECKOUT',
'CONNECT', 'COPY', 'DELETE',
'GET', 'HEAD', 'LINK',
'LOCK', 'M-SEARCH', 'MERGE',
'MKACTIVITY', 'MKCALENDAR', 'MKCOL',
'MOVE', 'NOTIFY', 'OPTIONS',
'PATCH', 'POST', 'PROPFIND',
'PROPPATCH', 'PURGE', 'PUT',
'REBIND', 'REPORT', 'SEARCH',
'SOURCE', 'SUBSCRIBE', 'TRACE',
'UNBIND', 'UNLINK', 'UNLOCK',
'UNSUBSCRIBE'
],
STATUS_CODES: {
'100': 'Continue',
'101': 'Switching Protocols',
'102': 'Processing',
'103': 'Early Hints',
'200': 'OK',
'201': 'Created',
'202': 'Accepted',
'203': 'Non-Authoritative Information',
'204': 'No Content',
'205': 'Reset Content',
'206': 'Partial Content',
'207': 'Multi-Status',
'208': 'Already Reported',
'226': 'IM Used',
'300': 'Multiple Choices',
'301': 'Moved Permanently',
'302': 'Found',
'303': 'See Other',
'304': 'Not Modified',
'305': 'Use Proxy',
'307': 'Temporary Redirect',
'308': 'Permanent Redirect',
'400': 'Bad Request',
'401': 'Unauthorized',
'402': 'Payment Required',
'403': 'Forbidden',
'404': 'Not Found',
'405': 'Method Not Allowed',
'406': 'Not Acceptable',
'407': 'Proxy Authentication Required',
'408': 'Request Timeout',
'409': 'Conflict',
'410': 'Gone',
'411': 'Length Required',
'412': 'Precondition Failed',
'413': 'Payload Too Large',
'414': 'URI Too Long',
'415': 'Unsupported Media Type',
'416': 'Range Not Satisfiable',
'417': 'Expectation Failed',
'418': "I'm a Teapot",
'421': 'Misdirected Request',
'422': 'Unprocessable Entity',
'423': 'Locked',
'424': 'Failed Dependency',
'425': 'Too Early',
'426': 'Upgrade Required',
'428': 'Precondition Required',
'429': 'Too Many Requests',
'431': 'Request Header Fields Too Large',
'451': 'Unavailable For Legal Reasons',
'500': 'Internal Server Error',
'501': 'Not Implemented',
'502': 'Bad Gateway',
'503': 'Service Unavailable',
'504': 'Gateway Timeout',
'505': 'HTTP Version Not Supported',
'506': 'Variant Also Negotiates',
'507': 'Insufficient Storage',
'508': 'Loop Detected',
'509': 'Bandwidth Limit Exceeded',
'510': 'Not Extended',
'511': 'Network Authentication Required'
},
Agent: [Function: Agent] { defaultMaxSockets: Infinity },
ClientRequest: [Function: ClientRequest],
IncomingMessage: [Function: IncomingMessage],
OutgoingMessage: [Function: OutgoingMessage],
Server: [Function: Server],
ServerResponse: [Function: ServerResponse],
createServer: [Function: createServer],
validateHeaderName: [Function: __node_internal_],
validateHeaderValue: [Function: __node_internal_],
get: [Function: get],
request: [Function: request],
setMaxIdleHTTPParsers: [Function: setMaxIdleHTTPParsers],
maxHeaderSize: [Getter],
globalAgent: [Getter/Setter]
},
'https:': {
Agent: [Function: Agent],
globalAgent: Agent {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 443,
protocol: 'https:',
options: [Object: null prototype],
requests: [Object: null prototype] {},
sockets: [Object: null prototype],
freeSockets: [Object: null prototype] {},
keepAliveMsecs: 1000,
keepAlive: false,
maxSockets: Infinity,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 1,
maxCachedSessions: 100,
_sessionCache: [Object],
[Symbol(kCapture)]: false
},
Server: [Function: Server],
createServer: [Function: createServer],
get: [Function: get],
request: [Function: request]
}
},
pathname: '/api/webhooks/<correct webhook id>'
},
_ended: false,
_ending: false,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_onNativeResponse: [Function (anonymous)],
_currentRequest: <ref *1> ClientRequest {
_events: [Object: null prototype] {
response: [Function: bound onceWrapper] {
listener: [Function (anonymous)]
},
abort: [Function (anonymous)],
aborted: [Function (anonymous)],
connect: [Function (anonymous)],
error: [Function (anonymous)],
socket: [Function (anonymous)],
timeout: [Function (anonymous)]
},
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
maxRequestsOnConnectionReached: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
strictContentLength: false,
_contentLength: null,
_hasBody: true,
_trailer: '',
finished: false,
_headerSent: false,
_closed: false,
socket: <ref *2> TLSSocket {
_tlsOptions: {
allowHalfOpen: undefined,
pipe: false,
secureContext: SecureContext { context: SecureContext {} },
isServer: false,
requestCert: true,
rejectUnauthorized: true,
session: Buffer(1711) [Uint8Array] [
48, 130, <a bunch more uint8s>,
... 1611 more items
],
ALPNProtocols: undefined,
requestOCSP: undefined,
enableTrace: undefined,
pskCallback: undefined,
highWaterMark: undefined,
onread: undefined,
signal: undefined
},
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
secureConnecting: false,
_SNICallback: null,
servername: 'discord.com',
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object: null prototype] {
close: [
[Function: onSocketCloseDestroySSL],
[Function],
[Function: onClose],
[Function: socketCloseListener]
],
end: [ [Function: onReadableStreamEnd], [Function: socketOnEnd] ],
newListener: [Function: keylogNewListener],
secure: [Function: onConnectSecure],
session: [Function (anonymous)],
free: [Function: onFree],
timeout: [Function: onTimeout],
agentRemove: [Function: onRemove],
error: [Function: socketErrorListener],
data: [Function: socketOnData],
drain: [Function: ondrain]
},
_eventsCount: 11,
connecting: false,
_hadError: true,
_parent: null,
_host: 'discord.com',
_closeAfterHandlingError: false,
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
<!--EndFragment-->
</body>
</html>
For reference, the docker that we push to ECR is over here: https://github.com/rumble-kong-league/sales-bot.
The above error does not happen immediately after a sale. Rather after about 10 minutes from the first sale. I suspect it's because of the retry
in your library, that tries to post the embed to discord multiple times. I doubt this error has anything to do with networking, since twitter posts work just fine on ecs on fargate.
What is slightly worrying is that it is making http requests, however discord webhook url is https.
This is running on v1CPU and 3GB RAM.
This happens on any collection.
No response
No response
No response
No response
No response
No response
No response
Hey I'm seeing a transaction with a value of 0 even though it shouldn't be, not clear what the problem is
tx 0x091fb66ab1c522b613cc06e9baf870951c71a220d013af8eb9227d98c6f8cdd8
will try to figure this out on my own if I can but the repo has changed so much I'm not sure where its failing.
Currently trying to set this up on an old Raspberry Pi 2 I have lying around.
I've can install and test successfully, but when I try and start (npm start
), I'm getting an error.
pi@raspberrypi:~/ethereum-nft-sales-bot $ npm start
> [email protected] start
> node --no-warnings dist/app.js
/home/pi/ethereum-nft-sales-bot/node_modules/imagescript/codecs/node/index.js:3
catch (err) { throw new Error('unsupported arch/platform: ' + err.message); }
^
Error: unsupported arch/platform: Cannot find module './bin/arm-linux.node'
I've a background in C development but JS and TS are totally new to me, but I'm wondering is there a basic compatibility issue between the components used in this project and the ARM architecture of a RPi 2?
Hey it seems like the app that used to be in this repo is gone and now it's an SDK?
Maybe you could add some documentation on how to build the onItemSold.ts file into something that can be run like the repo used to be structured?
Hey I set up the bot for my friends project https://opensea.io/collection/proofofpepe but it did like 100E+ volume in a few hours and twitter's API rate limited it to hell. It probably also got rate limited by etherscan too.
It would be great if in the .env
file there was a way to define some rate limits to keep the bot throttled and not get shut down
2022-07-31T06:52:47: Error: Given file is not valid, please check its type.
2022-07-31T06:52:47: at getFileHandle (/www/wwwroot/wBot/ethereum-nft-sales-bot/node_modules/twitter-api-v2/dist/v1/media-helpers.v1.js:61:15)
2022-07-31T06:52:47: at TwitterApiv1.getUploadMediaRequirements (/www/wwwroot/wBot/ethereum-nft-sales-bot/node_modules/twitter-api-v2/dist/v1/client.v1.write.js:352:69)
2022-07-31T06:52:47: at TwitterApiv1.uploadMedia (/www/wwwroot/wBot/ethereum-nft-sales-bot/node_modules/twitter-api-v2/dist/v1/client.v1.write.js:285:78)
2022-07-31T06:52:47: at tweet (file:///www/wwwroot/wBot/ethereum-nft-sales-bot/twitter/tweet.js:43:35)
2022-07-31T06:52:47: at runApp (file:///www/wwwroot/wBot/ethereum-nft-sales-bot/controllers/runApp.js:63:15)
2022-07-31T06:52:47: at runMicrotasks ()
2022-07-31T06:52:47: at processTicksAndRejections (node:internal/process/task_queues:96:5)
2022-07-31T06:52:47: at async Subscription. (file:///www/wwwroot/wBot/ethereum-nft-sales-bot/app.js:49:17)
Most NFT volume is currently being funneled through Blur, so adding support for their new contract would be ideal.
No response
Hey I'm trying to test this transaction 0x3c33ba5c1d8e9c37375cf1937ffce0b45e736e3d57c24ef256b4ce50d4f80ece
for contract 0x72A94e6c51CB06453B84c049Ce1E1312f7c05e2c
and getting this undefined length error
Running test for tx: 0x3c33ba5c1d8e9c37375cf1937ffce0b45e736e3d57c24ef256b4ce50d4f80ece
14 Wiiides sold on Opensea: Seaport โ๏ธ for 0.11309999000000001 ETH
https://etherscan.io/txData/0x3c33ba5c1d8e9c37375cf1937ffce0b45e736e3d57c24ef256b4ce50d4f80eceTypeError: Cannot read properties of undefined (reading 'length')
at tweet (file:///Users/sterlingcrispin/code/ethereum-nft-sales-bot/dist/twitter/tweet.js:50:21)
at runApp (file:///Users/sterlingcrispin/code/ethereum-nft-sales-bot/dist/controllers/runApp.js:39:15)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async file:///Users/sterlingcrispin/code/ethereum-nft-sales-bot/dist/app.js:43:13
โ ethereum-nft-sales-bot git:(mainorigin)
^1.0.6
It didn't notified of this NFT sold transaction.
Opensea: https://opensea.io/collection/opepen-edition
0x6339e5E072086621540D0362C4e3Cea0d643E114
0xa3f4e1ed59ef91bb7a67d3199092a812141b78b5c55d8219719d33340bd91cfd
No response
No response
No response
node.js (v16 or newer)
No response
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are currently rate-limited. Click on a checkbox below to force their creation now.
@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
)These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
@commitlint/cli
, @commitlint/config-conventional
, @commitlint/cz-commitlint
)chai
, @types/chai
)mocha
, @types/mocha
)@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
)sharp
, @types/sharp
)@commitlint/cli
, @commitlint/config-conventional
, @commitlint/cz-commitlint
).github/workflows/CI.yml
actions/checkout v3
actions/setup-node v3
actions/checkout v3
actions/setup-node v3
actions/checkout v3
actions/setup-node v3
.github/workflows/close-stale-issues-and-prs.yml
actions/stale v8
.github/workflows/release.yml
actions/checkout v3
actions/setup-node v3
package.json
async-retry ^1.3.3
ethers ^6.0.4
gifenc ^1.0.3
joi ^17.7.1
sharp ^0.32.0
twitter-api-v2 ^1.14.1
@commitlint/cli ^17.4.3
@commitlint/config-conventional ^17.4.3
@commitlint/cz-commitlint ^17.4.2
@semantic-release/changelog ^6.0.2
@semantic-release/git ^10.0.1
@types/async-retry ^1.4.4
@types/chai ^4.3.1
@types/mocha ^10.0.0
@types/node ^18.6.1
@types/sharp ^0.31.1
@typescript-eslint/eslint-plugin ^5.31.0
@typescript-eslint/parser ^5.31.0
chai ^4.3.6
commitizen ^4.3.0
cz-conventional-changelog ^3.3.0
dotenv ^16.0.3
eslint ^8.18.0
eslint-config-prettier ^8.5.0
eslint-plugin-prettier ^4.0.0
husky ^8.0.3
inquirer ^8.2.5
lint-staged ^13.1.2
mocha ^10.0.0
prettier ^2.7.1
rimraf ^5.0.0
semantic-release ^21.0.0
ts-mocha ^10.0.0
ts-node ^10.9.1
typedoc ^0.24.0
typedoc-plugin-markdown ^3.14.0
typescript ^4.9.5
node >=18.0.0
npm >=8.0.0
per the title.
No response
No response
No response
No response
No response
node.js (v18 or newer)
No response
I'm encountering sweeps completed by Opensea which when detected are appearing with mis-information.
e.g. A sweep of various tokens on a single contract
Correctly says the Qty and 'SWEPT', but the total sales price is incorrect. It is likely showing a price paid for one of the tokens.
The 'From' and 'To' only appears as if it's one token sold.
I notice in the src code that the embedded object appears differently for sweeps when the tx is from 'gem', 'genie' or 'blurSwap'. I suspect the Opensea sweep feature is not yet supported?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.