thirdweb 0.2.8 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -96
- package/dist/cli/index.js +5 -5
- package/dist/cli/index.js.map +1 -1
- package/package.json +8 -3
- package/src/cli/index.ts +17 -15
- package/src/common/error.ts +1 -191
- package/src/core/builder/brownie.ts +66 -0
- package/src/core/builder/build.ts +21 -1
- package/src/core/builder/builder-base.ts +14 -7
- package/src/core/builder/foundry.ts +4 -10
- package/src/core/builder/hardhat.ts +9 -14
- package/src/core/builder/truffle.ts +65 -0
- package/src/core/detection/brownie.ts +13 -0
- package/src/core/detection/detect.ts +36 -6
- package/src/core/detection/detector.ts +1 -1
- package/src/core/detection/foundry.ts +2 -2
- package/src/core/detection/hardhat.ts +2 -2
- package/src/core/detection/truffle.ts +13 -0
- package/src/core/helpers/storage.ts +3 -3
- package/src/core/interfaces/IStorage.ts +4 -4
- package/src/core/storage/ipfs-storage.ts +21 -15
- package/src/core/types/ProjectType.ts +6 -1
package/README.md
CHANGED
@@ -1,97 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# thirdweb cli
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
## 1. Extending ThirdwebContract
|
8
|
-
|
9
|
-
In order to publish a contract and get all the benefits of the thirdweb platform, your contract needs to extend `ThirdwebContract`.
|
10
|
-
|
11
|
-
From your project, add the thirdweb contracts dependency:
|
12
|
-
|
13
|
-
```shell
|
14
|
-
yarn add @thirdweb-dev/contracts@byoc
|
15
|
-
```
|
16
|
-
|
17
|
-
or with npm
|
18
|
-
|
19
|
-
```shell
|
20
|
-
npm i @thirdweb-dev/contracts@byoc
|
21
|
-
```
|
22
|
-
|
23
|
-
Once installed, in your Solidity contract you want to publish, import and extend `ThirdwebContract`. Here's an example:
|
24
|
-
|
25
|
-
```solidity
|
26
|
-
// SPDX-License-Identifier: MIT
|
27
|
-
pragma solidity ^0.8.4;
|
28
|
-
|
29
|
-
import "@thirdweb-dev/contracts/ThirdwebContract.sol";
|
30
|
-
|
31
|
-
contract HellowWorldContract is ThirdwebContract {
|
32
|
-
// your contract code
|
33
|
-
}
|
34
|
-
```
|
35
|
-
|
36
|
-
## 2. Publishing your contract
|
37
|
-
|
38
|
-
Once your contract code is setup like above, you can now publish it by running:
|
39
|
-
|
40
|
-
```shell
|
41
|
-
npx @thirdweb-dev/cli publish
|
42
|
-
```
|
43
|
-
|
44
|
-
Alternatively, you install the CLI as a global command on your machine:
|
45
|
-
|
46
|
-
```shell
|
47
|
-
npm i -g @thirdweb-dev/cli
|
48
|
-
thirdweb publish
|
49
|
-
```
|
50
|
-
|
51
|
-
This command will:
|
52
|
-
|
53
|
-
- auto-detect any contract that extends `ThirdwebContract` in your project
|
54
|
-
- compile your project
|
55
|
-
- Upload ABIs to IPFS
|
56
|
-
- Open the publish flow in your thirdweb dashboard in a browser
|
57
|
-
|
58
|
-
From the thirdweb dashboard, you can review and publish your contracts. Published contracts can be deployed via the dashboard on with our SDKs.
|
59
|
-
|
60
|
-
---
|
61
|
-
|
62
|
-
## Supported projects
|
63
|
-
|
64
|
-
To publish, you need to be in a directory that contains a project which the CLI is compatible
|
65
|
-
with. The projects we support so far:
|
66
|
-
|
67
|
-
- hardhat
|
68
|
-
|
69
|
-
Coming soon:
|
70
|
-
|
71
|
-
- forge
|
72
|
-
- truffle
|
73
|
-
|
74
|
-
---
|
75
|
-
|
76
|
-
## Running the examples
|
77
|
-
|
78
|
-
Clone the repo and run this command after installing the CLI tool:
|
79
|
-
|
80
|
-
```bash
|
81
|
-
$ cd examples/hardhat
|
82
|
-
$ thirdweb publish
|
83
|
-
```
|
84
|
-
|
85
|
-
## Local Development
|
86
|
-
|
87
|
-
The simplest way to work on the CLI locally is to:
|
88
|
-
|
89
|
-
1. Install the package locally
|
90
|
-
2. Run the `build:watch` command to compile any changes in realtime
|
91
|
-
|
92
|
-
```bash
|
93
|
-
$ npm install -g ./
|
94
|
-
$ yarn run build:watch
|
95
|
-
```
|
96
|
-
|
97
|
-
> TODO: figure out how to do the global local installation with yarn
|
3
|
+
This is a proxied package of the `@thirdweb-dev/cli` for convenient usage with `npx thirdweb`.
|
4
|
+
|
5
|
+
You can find the actual package [here](https://www.npmjs.com/package/@thirdweb-dev/cli).
|
6
|
+
|
package/dist/cli/index.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
-
var nt=Object.create;var W=Object.defineProperty;var st=Object.getOwnPropertyDescriptor;var it=Object.getOwnPropertyNames;var at=Object.getPrototypeOf,ct=Object.prototype.hasOwnProperty;var pt=(n,t)=>()=>(t||n((t={exports:{}}).exports,t),t.exports);var lt=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of it(t))!ct.call(n,o)&&o!==e&&W(n,o,{get:()=>t[o],enumerable:!(r=st(t,o))||r.enumerable});return n};var N=(n,t,e)=>(e=n!=null?nt(at(n)):{},lt(t||!n||!n.__esModule?W(e,"default",{value:n,enumerable:!0}):e,n));var X=pt((Wt,dt)=>{dt.exports={name:"thirdweb",main:"dist/cli/index.js",types:"dist/cli/index.d.ts",version:"0.2.8",repository:"git@github.com:thirdweb-dev/thirdweb-cli.git",author:"sdk@thirdweb.com",license:"MIT",engines:{node:">=14.0.0 <17"},devDependencies:{"@types/commander":"^2.12.2","@types/node":"^17.0.23","@types/update-notifier":"^5.1.0",hardhat:"^2.9.3","ts-node":"^10.7.0",tsc:"^2.0.4",tsup:"^5.12.1",typescript:"^4.6.3"},dependencies:{"@web-std/file":"^3.0.2",commander:"^9.1.0","form-data":"^4.0.0","isomorphic-fetch":"^3.0.0",open:"^8.4.0",tslog:"^3.3.3","update-notifier":"^5.1.0"},bin:{thirdweb:"./dist/cli/index.js"},scripts:{clean:"rm -rf dist/",cli:"node -r ts-node/register src/cli/index.ts",build:"yarn clean && tsup --env.NODE_ENV production --minify --format cjs --external hardhat --dts-resolve","build:watch":"yarn run build --watch",prepublishOnly:"yarn build","generate-thirdweb-package":"node scripts/generate-thirdweb-package.js"},files:["src/","dist/"],tsup:{entry:["src/cli/index.ts","src/helpers/hardhat-config-extractor.ts"],splitting:!1,sourcemap:!0,clean:!0}}});var j=class extends Error{constructor(t){super(`UPLOAD_FAILED: ${t}`)}};var C=class extends Error{constructor(t){super(`DUPLICATE_FILE_NAME_ERROR: File name ${t} was passed for more than one file.`)}};var T=class extends Error{constructor(e,r){super(`FETCH_FAILED: ${e}`);this.innerError=r}};var M="https://cloudflare-ipfs.com/ipfs/",G="https://upload.nftlabs.co",q="https://api.pinata.cloud/pinning/pinFileToIPFS",H="https://nightly.thirdweb.com";function D(n,t){let e=Object.keys(n);for(let r in e){let o=n[e[r]],s=o instanceof File||o instanceof Buffer;if(typeof o=="object"&&!s){D(o,t);continue}!s||(n[e[r]]=`ipfs://${t.splice(0,1)[0]}`)}return n}function O(n,t,e){let r=Object.keys(n);for(let o in r){let s=n[r[o]];if(n[r[o]]=B(s,t,e),Array.isArray(s))for(let p of s)O(p,t,e);typeof s=="object"&&O(s,t,e)}return n}function B(n,t,e){return typeof n=="string"&&n&&n.toLowerCase().includes(t)?n.replace(t,e):n}require("isomorphic-fetch");globalThis.FormData||(globalThis.FormData=require("form-data"));globalThis.File||(globalThis.File=require("@web-std/file").File);var S=class{constructor(t=M){this.gatewayUrl=`${t.replace(/\/$/,"")}/`}async upload(t,e,r){return`${await this.uploadBatch([t],0,e,r)}0`}async uploadBatch(t,e=0,r,o){let{cid:s,fileNames:p}=await this.uploadBatchWithCid(t,e,r,o),i=`ipfs://${s}/`,l=p.map(f=>`${i}${f}`);return{baseUri:i,metadataUris:l}}async getUploadToken(t){let e={"X-App-Name":`CONSOLE-TS-SDK-${t}`},r=await fetch(`${G}/grant`,{method:"GET",headers:e});if(!r.ok)throw new T("Failed to get upload token");return await r.text()}async get(t){let r=await(await this._get(t)).json();return O(r,"ipfs://",this.gatewayUrl)}async uploadMetadata(t,e,r){let{metadataUris:o}=await this.uploadMetadataBatch([t],0,e,r);return o[0]}async uploadMetadataBatch(t,e,r,o){let s=(await this.batchUploadProperties(t)).map(d=>JSON.stringify(d)),{cid:p,fileNames:i}=await this.uploadBatchWithCid(s,e,r,o),l=`ipfs://${p}/`,f=i.map(d=>`${l}${d}`);return{baseUri:l,metadataUris:f}}async _get(t){let e=t;t&&(e=B(t,"ipfs://",this.gatewayUrl));let r=await fetch(e);if(!r.ok)throw new Error(`Status code (!= 200) =${r.status}`);return r}async batchUploadProperties(t){let e=t.flatMap(i=>this.buildFilePropertiesMap(i,[]));if(e.length===0)return t;let{cid:r,fileNames:o}=await this.uploadBatchWithCid(e),s=[];for(let i of o)s.push(`${r}/${i}`);return await D(t,s)}buildFilePropertiesMap(t,e=[]){if(Array.isArray(t))t.forEach(r=>{this.buildFilePropertiesMap(r,e)});else if(t){let r=Object.values(t);for(let o of r)o instanceof File||o instanceof Buffer?e.push(o):typeof o=="object"&&this.buildFilePropertiesMap(o,e)}return e}async uploadBatchWithCid(t,e=0,r,o){let s=await this.getUploadToken(r||""),p={name:`CONSOLE-TS-SDK-${r}`,keyvalues:{sdk:"typescript",contractAddress:r,signerAddress:o}},i=new FormData,l=[];t.forEach((c,g)=>{let u="",m=c;if(c instanceof File){let y="";if(c.name){let b=c.name.lastIndexOf(".");b>-1&&(y=c.name.substring(b))}u=`${g+e}${y}`}else c instanceof Buffer||typeof c=="string"?u=`${g+e}`:c&&c.name&&(c==null?void 0:c.data)?(m=c==null?void 0:c.data,u=`${c.name}`):u=`${g+e}`;let $=`files/${u}`;if(l.indexOf(u)>-1)throw new C(u);l.push(u),typeof window>"u"?i.append("file",m,{filepath:$}):i.append("file",new Blob([m]),$)}),i.append("pinataMetadata",JSON.stringify(p));let f=await fetch(q,{method:"POST",headers:{Authorization:`Bearer ${s}`},body:i}),d=await f.json();if(!f.ok)throw console.log(d),new j("Failed to upload files to IPFS");return{cid:d.IpfsHash,fileNames:l}}};var Z=require("commander"),Q=N(require("path"));var V=require("fs");var Y=require("tslog"),a=new Y.Logger({minLevel:"info",displayFilePath:"hidden",displayFunctionName:!1,displayLoggerName:!1});var P=class{constructor(){this.projectType="foundry"}async matches(t){return a.debug("Checking if "+t+" is a Foundry project"),(0,V.existsSync)(t+"/foundry.toml")}};var L=require("fs");var F=class{constructor(){this.projectType="hardhat"}async matches(t){return a.debug("Checking if "+t+" is a Hardhat project"),(0,L.existsSync)(t+"/hardhat.config.js")||(0,L.existsSync)(t+"/hardhat.config.ts")}};async function A(n){let t=[new F,new P];for(let e of t)if(await e.matches(n))return e.projectType;return"unknown"}var U=require("child_process"),K=require("fs"),I=require("path");var x=require("fs"),E=require("path"),w=class{isThirdwebContract(t){try{return t.name==="setThirdwebInfo"&&t.inputs[0].internalType==="struct ThirdwebContract.ThirdwebInfo"}catch{return!1}}findFiles(t,e,r){if(!(0,x.existsSync)(t)){console.log("no dir ",t);return}for(var o=(0,x.readdirSync)(t),s=0;s<o.length;s++){var p=(0,E.join)(t,o[s]);if((0,E.basename)(p,".json")!=="ThirdwebContract"){var i=(0,x.statSync)(p);i.isDirectory()?this.findFiles(p,e,r):e.test(p)&&r.push(p)}}}};var v=class extends w{async compile(t){t.clean&&(a.info("Running forge clean"),(0,U.execSync)("forge clean")),a.info("Compiling..."),(0,U.execSync)("forge build");let e=(0,U.execSync)("forge config --json").toString(),r=JSON.parse(e),o=(0,I.join)(t.projectPath,r.out),s=[],p=[];this.findFiles(o,/^.*(?<!dbg)\.json$/,p);for(let i of p){a.debug("Processing:",i.replace(o,""));let l=(0,I.basename)(i,".json"),f=(0,K.readFileSync)(i,"utf-8"),d=JSON.parse(f),c=d.abi,g=d.bytecode.object;for(let u of c)if(this.isThirdwebContract(u)){s.find(m=>m.name===l)&&(a.error(`Found multiple contracts with name "${l}". Contract names should be unique.`),process.exit(1)),s.push({abi:c,bytecode:g,name:l});break}}return a.info("Detected thirdweb contracts:",s.map(i=>i.name).join(", ")),{contracts:s}}};var z=require("fs"),_=require("path");var R=require("child_process");var k=class extends w{async compile(t){t.clean&&(a.info("Running hardhat clean"),(0,R.execSync)("npx hardhat clean")),a.info("Compiling..."),(0,R.execSync)("npx hardhat compile");let e=(0,_.resolve)(__dirname,"../helpers/hardhat-config-extractor.js"),r=(0,R.execSync)(`npx hardhat run ${e} --no-compile`).toString(),o=JSON.parse(r);a.debug("successfully extracted hardhat config",o.paths);let s=o.paths.artifacts,p=o.paths.sources.replace(t.projectPath,""),i=(0,_.join)(s,p),l=[],f=[];this.findFiles(i,/^.*(?<!dbg)\.json$/,f);for(let d of f){a.debug("Processing:",d.replace(i,""));let c=(0,_.basename)(d,".json"),g=(0,z.readFileSync)(d,"utf-8"),u=JSON.parse(g),m=u.abi,$=u.bytecode;for(let y of m)if(this.isThirdwebContract(y)){l.find(b=>b.name===c)&&(a.error(`Found multiple contracts with name "${c}". Contract names should be unique.`),process.exit(1)),l.push({abi:m,bytecode:$,name:c});break}}return a.info("Detected thirdweb contracts:",l.map(d=>d.name).join(", ")),{contracts:l}}};async function J(n,t,e){switch(t){case"hardhat":return await new k().compile({name:"",projectPath:n,clean:e});case"foundry":return await new v().compile({name:"",projectPath:n,clean:e});default:throw new Error("Unknown project type")}}var tt=require("url"),et=N(require("open"));var rt=N(require("update-notifier")),$t=async()=>{let n=new Z.Command,t=new S,e=X(),r=e.version;console.info(`
|
2
|
+
var yt=Object.create;var z=Object.defineProperty;var bt=Object.getOwnPropertyDescriptor;var wt=Object.getOwnPropertyNames;var _t=Object.getPrototypeOf,Pt=Object.prototype.hasOwnProperty;var jt=(i,t)=>()=>(t||i((t={exports:{}}).exports,t),t.exports);var xt=(i,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of wt(t))!Pt.call(i,r)&&r!==e&&z(i,r,{get:()=>t[r],enumerable:!(o=bt(t,r))||o.enumerable});return i};var v=(i,t,e)=>(e=i!=null?yt(_t(i)):{},xt(t||!i||!i.__esModule?z(e,"default",{value:i,enumerable:!0}):e,i));var mt=jt((be,Ft)=>{Ft.exports={name:"thirdweb",main:"dist/cli/index.js",types:"dist/cli/index.d.ts",version:"0.3.1",repository:"git@github.com:thirdweb-dev/thirdweb-cli.git",author:"sdk@thirdweb.com",license:"MIT",engines:{node:">=14.0.0 <17"},devDependencies:{"@trivago/prettier-plugin-sort-imports":"^3.2.0","@types/inquirer":"^8.2.1","@types/node":"^17.0.23","@types/update-notifier":"^5.1.0",hardhat:"^2.9.3",prettier:"^2.6.2","ts-node":"^10.7.0",tsc:"^2.0.4",tsup:"^5.12.1",typescript:"^4.6.3"},dependencies:{"@web-std/file":"^3.0.2",commander:"^9.1.0","form-data":"^4.0.0",inquirer:"^8.2.3","isomorphic-fetch":"^3.0.0",open:"^8.4.0",tslog:"^3.3.3","update-notifier":"^5.1.0",yaml:"^2.0.1"},bin:{thirdweb:"./dist/cli/index.js"},scripts:{prettier:"prettier --write 'src/**/*'",clean:"rm -rf dist/",cli:"node -r ts-node/register src/cli/index.ts",build:"yarn clean && tsup --env.NODE_ENV production --minify --format cjs --external hardhat --dts-resolve","build:watch":"yarn run build --watch",prepublishOnly:"yarn build","generate-thirdweb-package":"node scripts/generate-thirdweb-package.js"},files:["src/","dist/"],tsup:{entry:["src/cli/index.ts","src/helpers/hardhat-config-extractor.ts"],splitting:!1,sourcemap:!0,clean:!0}}});var X="https://cloudflare-ipfs.com/ipfs/",Q="https://upload.nftlabs.co",Z="https://api.pinata.cloud/pinning/pinFileToIPFS",tt="https://nightly.thirdweb.com";var et=require("tslog"),n=new et.Logger({minLevel:"info",displayFilePath:"hidden",displayFunctionName:!1,displayLoggerName:!1});var P=require("fs"),F=require("path"),y=class{isThirdwebContract(t){try{return t.name==="setThirdwebInfo"&&t.inputs[0].internalType==="struct ThirdwebContract.ThirdwebInfo"}catch{return!1}}findFiles(t,e,o){if(!(0,P.existsSync)(t)){console.log("no dir ",t);return}let r=(0,P.readdirSync)(t);for(let s=0;s<r.length;s++){let c=(0,F.join)(t,r[s]);if((0,F.basename)(c,".json")==="ThirdwebContract")continue;let a=(0,P.statSync)(c);if(a.isDirectory()&&(0,F.basename)(c)==="dependencies"){n.debug('skipping "dependencies" directory');continue}a.isDirectory()?this.findFiles(c,e,o):e.test(c)&&o.push(c)}}};var ot=require("child_process"),b=require("fs"),j=require("path"),rt=require("yaml"),E=class extends y{async compile(t){var a;let e=(0,rt.parse)((0,b.readFileSync)((0,j.join)(t.projectPath,"brownie-config.yaml"),"utf-8")),o=(0,j.join)(t.projectPath,((a=e==null?void 0:e.project_structure)==null?void 0:a.build)||"./build");t.clean&&(n.info("Cleaning build directory"),(0,b.existsSync)(o)&&(0,b.rmdirSync)(o,{recursive:!0})),n.info("Compiling..."),(0,ot.execSync)("brownie compile");let r=(0,j.join)(o,"contracts/"),s=[],c=[];this.findFiles(r,/^.*(?<!dbg)\.json$/,c);for(let l of c){n.debug("Processing:",l.replace(r,""));let f=(0,j.basename)(l,".json"),d=(0,b.readFileSync)(l,"utf-8"),p=JSON.parse(d),h=p.abi,u=p.bytecode;for(let g of h)if(this.isThirdwebContract(g)){s.find(m=>m.name===f)&&(n.error(`Found multiple contracts with name "${f}". Contract names should be unique.`),process.exit(1)),s.push({abi:h,bytecode:u,name:f});break}}return{contracts:s}}};var I=require("child_process"),it=require("fs"),D=require("path"),N=class extends y{async compile(t){t.clean&&(n.info("Running forge clean"),(0,I.execSync)("forge clean")),n.info("Compiling..."),(0,I.execSync)("forge build");let e=(0,I.execSync)("forge config --json").toString(),o=JSON.parse(e),r=(0,D.join)(t.projectPath,o.out),s=[],c=[];this.findFiles(r,/^.*(?<!dbg)\.json$/,c);for(let a of c){n.debug("Processing:",a.replace(r,""));let l=(0,D.basename)(a,".json"),f=(0,it.readFileSync)(a,"utf-8"),d=JSON.parse(f),p=d.abi,h=d.bytecode.object;for(let u of p)if(this.isThirdwebContract(u)){s.find(g=>g.name===l)&&(n.error(`Found multiple contracts with name "${l}". Contract names should be unique.`),process.exit(1)),s.push({abi:p,bytecode:h,name:l});break}}return{contracts:s}}};var B=require("child_process"),nt=require("fs"),x=require("path"),R=class extends y{async compile(t){t.clean&&(n.info("Running hardhat clean"),(0,B.execSync)("npx hardhat clean")),n.info("Compiling..."),(0,B.execSync)("npx hardhat compile");let e=(0,x.resolve)(__dirname,"../helpers/hardhat-config-extractor.js"),o=(0,B.execSync)(`npx hardhat run ${e} --no-compile`).toString(),r=JSON.parse(o);n.debug("successfully extracted hardhat config",r.paths);let s=r.paths.artifacts,c=r.paths.sources.replace(t.projectPath,""),a=(0,x.join)(s,c),l=[],f=[];this.findFiles(a,/^.*(?<!dbg)\.json$/,f);for(let d of f){n.debug("Processing:",d.replace(a,""));let p=(0,x.basename)(d,".json"),h=(0,nt.readFileSync)(d,"utf-8"),u=JSON.parse(h),g=u.abi,m=u.bytecode;for(let w of g)if(this.isThirdwebContract(w)){l.find(_=>_.name===p)&&(n.error(`Found multiple contracts with name "${p}". Contract names should be unique.`),process.exit(1)),l.push({abi:g,bytecode:m,name:p});break}}return{contracts:l}}};var st=require("child_process"),C=require("fs"),T=require("path"),J=class extends y{async compile(t){let e=require((0,T.join)(t.projectPath,"truffle-config.js")),o=(0,T.join)(t.projectPath,e.contracts_build_directory||"./build/contracts");t.clean&&(n.info("Cleaning build directory"),(0,C.existsSync)(o)&&(0,C.rmdirSync)(o,{recursive:!0})),n.info("Compiling..."),(0,st.execSync)("npx truffle compile");let r=[],s=[];this.findFiles(o,/^.*(?<!dbg)\.json$/,s);for(let c of s){n.debug("Processing:",c.replace(o,""));let a=(0,T.basename)(c,".json"),l=(0,C.readFileSync)(c,"utf-8"),f=JSON.parse(l),d=f.abi,p=f.bytecode;for(let h of d)if(this.isThirdwebContract(h)){r.find(u=>u.name===a)&&(n.error(`Found multiple contracts with name "${a}". Contract names should be unique.`),process.exit(1)),r.push({abi:d,bytecode:p,name:a});break}}return{contracts:r}}};async function G(i,t,e){switch(t){case"hardhat":return await new R().compile({name:"",projectPath:i,clean:e});case"foundry":return await new N().compile({name:"",projectPath:i,clean:e});case"truffle":return await new J().compile({name:"",projectPath:i,clean:e});case"brownie":return await new E().compile({name:"",projectPath:i,clean:e});default:throw new Error("Unknown project type")}}var at=require("fs"),S=class{constructor(){this.projectType="brownie"}matches(t){return n.debug("Checking if "+t+" is a Foundry project"),(0,at.existsSync)(t+"/brownie-config.yaml")}};var ct=require("fs"),O=class{constructor(){this.projectType="foundry"}matches(t){return n.debug("Checking if "+t+" is a Foundry project"),(0,ct.existsSync)(t+"/foundry.toml")}};var H=require("fs"),U=class{constructor(){this.projectType="hardhat"}matches(t){return n.debug("Checking if "+t+" is a Hardhat project"),(0,H.existsSync)(t+"/hardhat.config.js")||(0,H.existsSync)(t+"/hardhat.config.ts")}};var pt=require("fs"),k=class{constructor(){this.projectType="truffle"}matches(t){return n.debug("Checking if "+t+" is a Truffle project"),(0,pt.existsSync)(t+"/truffle-config.js")}};var lt=v(require("inquirer"));async function V(i){let e=[new U,new O,new k,new S].filter(s=>s.matches(i)).map(s=>s.projectType);if(!e.length)return"unknown";if(e.length===1)return n.info("Detected project type:",e[0]),e[0];n.info("Detected multiple possible build tools:",e.map(s=>`"${s}"`).join(", "));let o="How would you like to compile your contracts";return(await lt.default.prompt({type:"list",choices:e,name:o}))[o]}var L=class extends Error{constructor(t){super(`UPLOAD_FAILED: ${t}`)}},A=class extends Error{constructor(t){super(`DUPLICATE_FILE_NAME_ERROR: File name ${t} was passed for more than one file.`)}},W=class extends Error{constructor(e,o){super(`FETCH_FAILED: ${e}`);this.innerError=o}};function K(i,t){let e=Object.keys(i);for(let o in e){let r=i[e[o]],s=r instanceof File||r instanceof Buffer;if(typeof r=="object"&&!s){K(r,t);continue}!s||(i[e[o]]=`ipfs://${t.splice(0,1)[0]}`)}return i}function M(i,t,e){let o=Object.keys(i);for(let r in o){let s=i[o[r]];if(i[o[r]]=Y(s,t,e),Array.isArray(s))for(let c of s)M(c,t,e);typeof s=="object"&&M(s,t,e)}return i}function Y(i,t,e){return typeof i=="string"&&i&&i.toLowerCase().includes(t)?i.replace(t,e):i}var Ct=process.emitWarning;process.emitWarning=()=>{};require("isomorphic-fetch");globalThis.FormData||(globalThis.FormData=require("form-data"));globalThis.File||(globalThis.File=require("@web-std/file").File);process.emitWarning=Ct;var q=class{constructor(t=X){this.gatewayUrl=`${t.replace(/\/$/,"")}/`}async upload(t,e,o){return`${await this.uploadBatch([t],0,e,o)}0`}async uploadBatch(t,e=0,o,r){let{cid:s,fileNames:c}=await this.uploadBatchWithCid(t,e,o,r),a=`ipfs://${s}/`,l=c.map(f=>`${a}${f}`);return{baseUri:a,metadataUris:l}}async getUploadToken(t){let e={"X-App-Name":`CONSOLE-TS-SDK-${t}`},o=await fetch(`${Q}/grant`,{method:"GET",headers:e});if(!o.ok)throw new W("Failed to get upload token");return await o.text()}async get(t){let o=await(await this._get(t)).json();return M(o,"ipfs://",this.gatewayUrl)}async uploadMetadata(t,e,o){let{metadataUris:r}=await this.uploadMetadataBatch([t],0,e,o);return r[0]}async uploadMetadataBatch(t,e,o,r){let s=(await this.batchUploadProperties(t)).map(d=>JSON.stringify(d)),{cid:c,fileNames:a}=await this.uploadBatchWithCid(s,e,o,r),l=`ipfs://${c}/`,f=a.map(d=>`${l}${d}`);return{baseUri:l,metadataUris:f}}async _get(t){let e=t;t&&(e=Y(t,"ipfs://",this.gatewayUrl));let o=await fetch(e);if(!o.ok)throw new Error(`Status code (!= 200) =${o.status}`);return o}async batchUploadProperties(t){let e=t.flatMap(a=>this.buildFilePropertiesMap(a,[]));if(e.length===0)return t;let{cid:o,fileNames:r}=await this.uploadBatchWithCid(e),s=[];for(let a of r)s.push(`${o}/${a}`);return await K(t,s)}buildFilePropertiesMap(t,e=[]){if(Array.isArray(t))t.forEach(o=>{this.buildFilePropertiesMap(o,e)});else if(t){let o=Object.values(t);for(let r of o)r instanceof File||r instanceof Buffer?e.push(r):typeof r=="object"&&this.buildFilePropertiesMap(r,e)}return e}async uploadBatchWithCid(t,e=0,o,r){let s=await this.getUploadToken(o||""),c={name:`CONSOLE-TS-SDK-${o}`,keyvalues:{sdk:"typescript",contractAddress:o,signerAddress:r}},a=new FormData,l=[];t.forEach((p,h)=>{let u="",g=p;if(p instanceof File){let w="";if(p.name){let _=p.name.lastIndexOf(".");_>-1&&(w=p.name.substring(_))}u=`${h+e}${w}`}else p instanceof Buffer||typeof p=="string"?u=`${h+e}`:p&&p.name&&(p==null?void 0:p.data)?(g=p==null?void 0:p.data,u=`${p.name}`):u=`${h+e}`;let m=`files/${u}`;if(l.indexOf(u)>-1)throw new A(u);l.push(u),typeof window>"u"?a.append("file",g,{filepath:m}):a.append("file",new Blob([g]),m)}),a.append("pinataMetadata",JSON.stringify(c));let f=await fetch(Z,{method:"POST",headers:{Authorization:`Bearer ${s}`},body:a}),d=await f.json();if(!f.ok)throw console.log(d),new L("Failed to upload files to IPFS");return{cid:d.IpfsHash,fileNames:l}}};var ft=require("commander"),dt=v(require("open")),ut=v(require("path")),$t=v(require("update-notifier")),ht=require("url"),Tt=async()=>{let i=new ft.Command,t=new q,e=mt(),o=e.version;console.info(`
|
3
3
|
$$\\ $$\\ $$\\ $$\\ $$\\
|
4
4
|
$$ | $$ | \\__| $$ | $$ |
|
5
5
|
$$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$$\\
|
@@ -8,10 +8,10 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
|
8
8
|
$$ |$$\\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
|
9
9
|
\\$$$$ |$$ | $$ |$$ |$$ | \\$$$$$$$ |\\$$$$$\\$$$$ |\\$$$$$$$\\ $$$$$$$ |
|
10
10
|
\\____/ \\__| \\__|\\__|\\__| \\_______| \\_____\\____/ \\_______|\\_______/ `),console.info(`
|
11
|
-
\u{1F48E} thirdweb-cli v${
|
12
|
-
`),(0
|
11
|
+
\u{1F48E} thirdweb-cli v${o} \u{1F48E}
|
12
|
+
`),(0,$t.default)({pkg:e,shouldNotifyInNpmScript:!0,updateCheckInterval:0}).notify(),i.name("thirdweb-cli").description("Official thirdweb command line interface").version(o,"-v, --version","output the current version"),i.command("publish").description("Compile & publish a project").option("-p, --path <project-path>","path to project",".").option("--dry-run","dry run (skip actually publishing)").option("-c, --clean","clean artifacts before compiling").option("-d, --debug","show debug logs").action(async r=>{n.setSettings({minLevel:r.debug?"debug":"info"});let s=process.cwd();r.path&&(n.debug("Overriding project path to "+r.path),s=r.path.startsWith("/")?r.path:ut.default.resolve(`${s}/${r.path}`)),n.debug("Publishing project at path "+s);let c=await V(s);c==="unknown"&&(n.error("Unable to detect project type"),process.exit(1));let a=await G(s,c,r.clean);a.contracts.length==0&&(n.error("No thirdweb contract detected. Extend ThirdwebContract to publish your own contracts."),process.exit(1)),n.info("Detected thirdweb contracts:",a.contracts.map(m=>`"${m.name}"`).join(", ")),n.info("Project compiled successfully"),r.dryRun&&(n.info("Dry run, skipping publish"),process.exit(0)),n.info("Uploading contract data...");let l=a.contracts.map(m=>m.bytecode),f=a.contracts.map(m=>JSON.stringify(m.abi)),{metadataUris:d}=await t.uploadBatch(l),{metadataUris:p}=await t.uploadBatch(f),h=[];for(let m=0;m<a.contracts.length;m++){let w=d[m],_=p[m],gt=a.contracts[m].name;h.push(JSON.stringify({name:gt,bytecodeUri:w,abiUri:_}))}let{metadataUris:u}=await t.uploadBatch(h);n.info("Upload successful");let g=new ht.URL(tt+"/contracts/publish");for(let m of u)g.searchParams.append("ipfs",m.replace("ipfs://",""));n.info(`Go to this link to publish your contracts:
|
13
13
|
|
14
|
-
${
|
14
|
+
${g}
|
15
15
|
|
16
|
-
`),(0,
|
16
|
+
`),(0,dt.default)(g.toString())}),await i.parseAsync()};Tt().then(()=>{process.exit(0)}).catch(i=>{n.error(i),process.exit(1)});
|
17
17
|
//# sourceMappingURL=index.js.map
|
package/dist/cli/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../src/common/error.ts","../../src/constants/urls.ts","../../src/core/helpers/storage.ts","../../src/core/storage/ipfs-storage.ts","../../src/cli/index.ts","../../src/core/detection/foundry.ts","../../src/core/helpers/logger.ts","../../src/core/detection/hardhat.ts","../../src/core/detection/detect.ts","../../src/core/builder/foundry.ts","../../src/core/builder/builder-base.ts","../../src/core/builder/hardhat.ts","../../src/core/builder/build.ts"],"sourcesContent":["/**\n * Error that may get thrown if IPFS returns nothing for a given uri.\n * @internal\n */\nexport class NotFoundError extends Error {\n /** @internal */\n constructor(identifier?: string) {\n super(identifier ? `Object with id ${identifier} NOT FOUND` : \"NOT_FOUND\");\n }\n}\n\n/**\n * Error that may get thrown if an invalid address was passed\n * @internal\n */\nexport class InvalidAddressError extends Error {\n /** @internal */\n constructor(address?: string) {\n super(\n address ? `'${address}' is an invalid address` : \"Invalid address passed\"\n );\n }\n}\n\n/**\n * @internal\n */\nexport class MissingRoleError extends Error {\n /** @internal */\n /** @internal */\n constructor(address: string, role: string) {\n super(`MISSING ROLE: ${address} does not have the '${role}' role`);\n }\n}\n\n/**\n * @internal\n */\nexport class AssetNotFoundError extends Error {\n /** @internal */\n /** @internal */\n constructor(message = \"The asset you're trying to use could not be found.\") {\n super(`message: ${message}`);\n }\n}\n\n/**\n * @internal\n */\nexport class UploadError extends Error {\n /** @internal */\n constructor(message: string) {\n super(`UPLOAD_FAILED: ${message}`);\n }\n}\n\n/**\n * @internal\n */\nexport class FileNameMissingError extends Error {\n /** @internal */\n constructor() {\n super(\"File name is required when object is not a `File` type object.\");\n }\n}\n\n/**\n * @internal\n */\nexport class DuplicateFileNameError extends Error {\n /** @internal */\n constructor(fileName: string) {\n super(\n `DUPLICATE_FILE_NAME_ERROR: File name ${fileName} was passed for more than one file.`\n );\n }\n}\n\n/**\n * @internal\n */\nexport class NotEnoughTokensError extends Error {\n /** @internal */\n constructor(contractAddress: string, quantity: number, available: number) {\n super(\n `BALANCE ERROR: you do not have enough balance on contract ${contractAddress} to use ${quantity} tokens. You have ${available} tokens available.`\n );\n }\n}\n\n/**\n * @internal\n */\nexport class MissingOwnerRoleError extends Error {\n /** @internal */\n constructor() {\n super(`LIST ERROR: you should be the owner of the token to list it.`);\n }\n}\n\n/**\n * @internal\n */\nexport class QuantityAboveLimitError extends Error {\n /** @internal */\n constructor(quantity: string) {\n super(`BUY ERROR: You cannot buy more than ${quantity} tokens`);\n }\n}\n\n/**\n * Thrown when data fails to fetch from storage.\n * @internal\n */\nexport class FetchError extends Error {\n public innerError?: Error;\n\n /** @internal */\n constructor(message: string, innerError?: Error) {\n super(`FETCH_FAILED: ${message}`);\n this.innerError = innerError;\n }\n}\n\n/**\n * Thrown when attempting to create a snapshot with duplicate leafs\n * @internal\n */\nexport class DuplicateLeafsError extends Error {\n constructor(message?: string) {\n super(`DUPLICATE_LEAFS${message ? ` : ${message}` : \"\"}`);\n }\n}\n\n/**\n * Thrown when attempting to update/cancel an auction that already started\n * @internal\n */\nexport class AuctionAlreadyStartedError extends Error {\n constructor(id?: string) {\n super(\n `Auction already started with existing bid${id ? `, id: ${id}` : \"\"}`\n );\n }\n}\n\n/**\n * @internal\n */\nexport class FunctionDeprecatedError extends Error {\n /** @internal */\n constructor(message: string) {\n super(`FUNCTION DEPRECATED. ${message ? `Use ${message} instead` : \"\"}`);\n }\n}\n/**\n * Thrown when trying to retrieve a listing from a marketplace that doesn't exist\n * @internal\n */\nexport class ListingNotFoundError extends Error {\n constructor(marketplaceContractAddress: string, listingId?: string) {\n super(\n `Could not find listing.${\n marketplaceContractAddress\n ? ` marketplace address: ${marketplaceContractAddress}`\n : \"\"\n }${listingId ? ` listing id: ${listingId}` : \"\"}`\n );\n }\n}\n\n/**\n * Thrown when trying to retrieve a listing of the wrong type\n * @internal\n */\nexport class WrongListingTypeError extends Error {\n constructor(\n marketplaceContractAddress: string,\n listingId?: string,\n actualType?: string,\n expectedType?: string\n ) {\n super(\n `Incorrect listing type. Are you sure you're using the right method?.${\n marketplaceContractAddress\n ? ` marketplace address: ${marketplaceContractAddress}`\n : \"\"\n }${listingId ? ` listing id: ${listingId}` : \"\"}${\n expectedType ? ` expected type: ${expectedType}` : \"\"\n }${actualType ? ` actual type: ${actualType}` : \"\"}`\n );\n }\n}\n\n/**\n * Thrown when attempting to transfer an asset that has restricted transferability\n * @internal\n */\nexport class RestrictedTransferError extends Error {\n constructor(assetAddress?: string) {\n super(\n `Failed to transfer asset, transfer is restricted.${\n assetAddress ? ` Address : ${assetAddress}` : \"\"\n }`\n );\n }\n}\n\n/**\n * Thrown when attempting to execute an admin-role function.\n * @internal\n */\nexport class AdminRoleMissingError extends Error {\n constructor(\n address?: string,\n contractAddress?: string,\n message = \"Failed to execute transaction\"\n ) {\n super(\n `${message}, admin role is missing${\n address ? ` on address: ${address}` : \"\"\n }${contractAddress ? ` on contract: ${contractAddress}` : \"\"}`\n );\n }\n}\n","/**\n * @internal\n */\nexport const DEFAULT_IPFS_GATEWAY = \"https://cloudflare-ipfs.com/ipfs/\";\n\n/**\n * @internal\n */\nexport const TW_IPFS_SERVER_URL = \"https://upload.nftlabs.co\";\n\n/**\n * @internal\n */\nexport const PINATA_IPFS_URL = `https://api.pinata.cloud/pinning/pinFileToIPFS`;\n\n/**\n * @internal\n */\nexport const THIRDWEB_URL = `https://nightly.thirdweb.com`;\n","import { Json } from \"../types\";\n\n/**\n * Given a map of file hashes to ipfs uris, this function will hash\n * all properties recursively and replace them with the ipfs uris\n * from the map passed in. If a hash is missing from the map, the function\n * will throw an error.\n *\n * @internal\n *\n * @param object - The object to recursively process\n * @param cids - The array of file hashes to ipfs uris in the recurse order\n * @returns - The processed metadata with properties pointing at ipfs in place of `File | Buffer`\n */\nexport function replaceFilePropertiesWithHashes(\n object: Record<string, any>,\n cids: string[]\n) {\n const keys = Object.keys(object);\n for (const key in keys) {\n const val = object[keys[key]];\n const isFile = val instanceof File || val instanceof Buffer;\n if (typeof val === \"object\" && !isFile) {\n replaceFilePropertiesWithHashes(val, cids);\n continue;\n }\n\n if (!isFile) {\n continue;\n }\n\n object[keys[key]] = `ipfs://${cids.splice(0, 1)[0]}`;\n }\n return object;\n}\n\n/**\n * Replaces all ipfs:// hashes (or any other scheme) with gateway url\n * @param object\n * @param scheme\n * @param gatewayUrl\n */\nexport function replaceHashWithGatewayUrl(\n object: Record<string, any>,\n scheme: string,\n gatewayUrl: string\n): Record<string, any> {\n const keys = Object.keys(object);\n for (const key in keys) {\n const val = object[keys[key]];\n object[keys[key]] = resolveGatewayUrl(val, scheme, gatewayUrl);\n if (Array.isArray(val)) {\n for (const el of val) {\n replaceHashWithGatewayUrl(el, scheme, gatewayUrl);\n }\n }\n if (typeof val === \"object\") {\n replaceHashWithGatewayUrl(val, scheme, gatewayUrl);\n }\n }\n return object;\n}\n\n/**\n * Resolves the full URL of a file for a given gateway.\n *\n * For example, if the hash of a file is `ipfs://bafkreib3u2u6ir2fsl5nkuwixfsb3l4xehri3psjv5yga4inuzsjunk2sy`, then the URL will be:\n * \"https://cloudflare-ipfs.com/ipfs/bafkreibnwjhx5s3r2rggdoy3hw7lr7wmgy4bas35oky3ed6eijklk2oyvq\"\n * if the gateway is `cloudflare-ipfs.com`.\n *\n * @param ipfsHash\n * @param scheme\n * @param gatewayUrl\n */\nexport function resolveGatewayUrl<T extends Json>(\n ipfsHash: T,\n scheme: string,\n gatewayUrl: string\n): T {\n if (typeof ipfsHash === \"string\") {\n return ipfsHash && ipfsHash.toLowerCase().includes(scheme)\n ? (ipfsHash.replace(scheme, gatewayUrl) as T)\n : ipfsHash;\n } else {\n return ipfsHash;\n }\n}\n","import {\n DuplicateFileNameError,\n FetchError,\n UploadError,\n} from \"../../common/error\";\nimport {\n DEFAULT_IPFS_GATEWAY,\n PINATA_IPFS_URL,\n TW_IPFS_SERVER_URL,\n} from \"../../constants/urls\";\nimport { IStorage } from \"../interfaces/IStorage\";\nimport { FileOrBuffer, JsonObject } from \"../types\";\nimport {\n replaceFilePropertiesWithHashes,\n replaceHashWithGatewayUrl,\n resolveGatewayUrl,\n} from \"../helpers/storage\";\n\nrequire(\"isomorphic-fetch\");\n\nif (!globalThis.FormData) {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n globalThis.FormData = require(\"form-data\");\n}\n\nif (!globalThis.File) {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n globalThis.File = require(\"@web-std/file\").File;\n}\n\n/**\n * @internal\n */\ninterface CidWithFileName {\n // base cid of the directory\n cid: string;\n\n // file name of the file without cid\n fileNames: string[];\n}\n\n/**\n * IPFS Storage implementation, accepts custom IPFS gateways\n * @public\n */\nexport class IpfsStorage implements IStorage {\n private gatewayUrl: string;\n\n constructor(gatewayUrl: string = DEFAULT_IPFS_GATEWAY) {\n this.gatewayUrl = `${gatewayUrl.replace(/\\/$/, \"\")}/`;\n }\n\n /**\n * {@inheritDoc IStorage.upload}\n */\n public async upload(\n data: string | FileOrBuffer,\n contractAddress?: string,\n signerAddress?: string\n ): Promise<string> {\n const cid = await this.uploadBatch(\n [data],\n 0,\n contractAddress,\n signerAddress\n );\n return `${cid}0`;\n }\n\n /**\n * {@inheritDoc IStorage.uploadBatch}\n */\n public async uploadBatch(\n files: (string | FileOrBuffer)[],\n fileStartNumber = 0,\n contractAddress?: string,\n signerAddress?: string\n ) {\n const { cid, fileNames } = await this.uploadBatchWithCid(\n files,\n fileStartNumber,\n contractAddress,\n signerAddress\n );\n\n const baseUri = `ipfs://${cid}/`;\n const uris = fileNames.map((filename) => `${baseUri}${filename}`);\n\n return {\n baseUri,\n metadataUris: uris,\n };\n }\n\n /**\n * {@inheritDoc IStorage.getUploadToken}\n */\n public async getUploadToken(contractAddress: string): Promise<string> {\n const headers = {\n \"X-App-Name\": `CONSOLE-TS-SDK-${contractAddress}`,\n };\n const res = await fetch(`${TW_IPFS_SERVER_URL}/grant`, {\n method: \"GET\",\n headers,\n });\n if (!res.ok) {\n throw new FetchError(`Failed to get upload token`);\n }\n const body = await res.text();\n return body;\n }\n\n /**\n * {@inheritDoc IStorage.get}\n */\n public async get(hash: string): Promise<Record<string, any>> {\n const res = await this._get(hash);\n const json = await res.json();\n return replaceHashWithGatewayUrl(json, \"ipfs://\", this.gatewayUrl);\n }\n\n /**\n * {@inheritDoc IStorage.uploadMetadata}\n */\n public async uploadMetadata(\n metadata: JsonObject,\n contractAddress?: string,\n signerAddress?: string\n ): Promise<string> {\n // since there's only single object, always use the first index\n const { metadataUris } = await this.uploadMetadataBatch(\n [metadata],\n 0,\n contractAddress,\n signerAddress\n );\n return metadataUris[0];\n }\n\n /**\n * {@inheritDoc IStorage.uploadMetadataBatch}\n */\n public async uploadMetadataBatch(\n metadatas: JsonObject[],\n fileStartNumber?: number,\n contractAddress?: string,\n signerAddress?: string\n ) {\n const metadataToUpload = (await this.batchUploadProperties(metadatas)).map(\n (m: any) => JSON.stringify(m)\n );\n\n const { cid, fileNames } = await this.uploadBatchWithCid(\n metadataToUpload,\n fileStartNumber,\n contractAddress,\n signerAddress\n );\n\n const baseUri = `ipfs://${cid}/`;\n const uris = fileNames.map((filename) => `${baseUri}${filename}`);\n\n return {\n baseUri,\n metadataUris: uris,\n };\n }\n\n /** *************************\n * PRIVATE FUNCTIONS\n *************************/\n\n private async _get(hash: string): Promise<Response> {\n let uri = hash;\n if (hash) {\n uri = resolveGatewayUrl(hash, \"ipfs://\", this.gatewayUrl);\n }\n const result = await fetch(uri);\n if (!result.ok) {\n throw new Error(`Status code (!= 200) =${result.status}`);\n }\n return result;\n }\n\n /**\n * Pre-processes metadata and uploads all file properties\n * to storage in *bulk*, then performs a string replacement of\n * all file properties -\\> the resulting ipfs uri. This is\n * called internally by `uploadMetadataBatch`.\n *\n * @internal\n *\n * @param metadata - The metadata to recursively process\n * @returns - The processed metadata with properties pointing at ipfs in place of `File | Buffer`\n */\n private async batchUploadProperties(metadatas: JsonObject[]) {\n const filesToUpload = metadatas.flatMap((m) =>\n this.buildFilePropertiesMap(m, [])\n );\n if (filesToUpload.length === 0) {\n return metadatas;\n }\n const { cid, fileNames } = await this.uploadBatchWithCid(filesToUpload);\n\n const cids = [];\n // recurse ordered array\n for (const filename of fileNames) {\n cids.push(`${cid}/${filename}`);\n }\n\n const finalMetadata = await replaceFilePropertiesWithHashes(\n metadatas,\n cids\n );\n return finalMetadata;\n }\n\n /**\n * This function recurisely traverses an object and hashes any\n * `Buffer` or `File` objects into the returned map.\n *\n * @param object - the Json Object\n * @param files - The running array of files or buffer to upload\n * @returns - The final map of all hashes to files\n */\n private buildFilePropertiesMap(\n object: JsonObject,\n files: (File | Buffer)[] = []\n ): (File | Buffer)[] {\n if (Array.isArray(object)) {\n object.forEach((element) => {\n this.buildFilePropertiesMap(element, files);\n });\n } else if (object) {\n const values = Object.values(object);\n for (const val of values) {\n if (val instanceof File || val instanceof Buffer) {\n files.push(val);\n } else if (typeof val === \"object\") {\n this.buildFilePropertiesMap(val as JsonObject, files);\n }\n }\n }\n return files;\n }\n\n private async uploadBatchWithCid(\n files: (string | FileOrBuffer)[],\n fileStartNumber = 0,\n contractAddress?: string,\n signerAddress?: string\n ): Promise<CidWithFileName> {\n const token = await this.getUploadToken(contractAddress || \"\");\n const metadata = {\n name: `CONSOLE-TS-SDK-${contractAddress}`,\n keyvalues: {\n sdk: \"typescript\",\n contractAddress,\n signerAddress,\n },\n };\n const data = new FormData();\n const fileNames: string[] = [];\n files.forEach((file, i) => {\n let fileName = \"\";\n let fileData = file;\n // if it is a file, we passthrough the file extensions,\n // if it is a buffer or string, the filename would be fileStartNumber + index\n // if it is a buffer or string with names, the filename would be the name\n if (file instanceof File) {\n let extensions = \"\";\n if (file.name) {\n const extensionStartIndex = file.name.lastIndexOf(\".\");\n if (extensionStartIndex > -1) {\n extensions = file.name.substring(extensionStartIndex);\n }\n }\n fileName = `${i + fileStartNumber}${extensions}`;\n } else if (file instanceof Buffer || typeof file === \"string\") {\n fileName = `${i + fileStartNumber}`;\n } else if (file && file.name && file?.data) {\n fileData = file?.data;\n fileName = `${file.name}`;\n } else {\n // default behavior\n fileName = `${i + fileStartNumber}`;\n }\n\n const filepath = `files/${fileName}`;\n if (fileNames.indexOf(fileName) > -1) {\n throw new DuplicateFileNameError(fileName);\n }\n fileNames.push(fileName);\n if (typeof window === \"undefined\") {\n data.append(\"file\", fileData as any, { filepath } as any);\n } else {\n // browser does blob things, filepath is parsed differently on browser vs node.\n // pls pinata?\n data.append(\"file\", new Blob([fileData as any]), filepath);\n }\n });\n\n data.append(\"pinataMetadata\", JSON.stringify(metadata));\n const res = await fetch(PINATA_IPFS_URL, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n body: data as any,\n });\n const body = await res.json();\n if (!res.ok) {\n console.log(body);\n throw new UploadError(\"Failed to upload files to IPFS\");\n }\n return {\n cid: body.IpfsHash,\n fileNames,\n };\n }\n}\n","#!/usr/bin/env node\n\nimport { IpfsStorage } from \"./../core/storage/ipfs-storage\";\nimport { Command } from \"commander\";\nimport path from \"path\";\nimport detect from \"../core/detection/detect\";\nimport build from \"../core/builder/build\";\nimport { THIRDWEB_URL } from \"../constants/urls\";\nimport { URL } from \"url\";\nimport open from \"open\";\nimport { Contract } from \"../core/interfaces/Contract\";\nimport { logger } from \"../core/helpers/logger\";\nimport updateNotifier from \"update-notifier\";\n\nconst main = async () => {\n const program = new Command();\n\n // TODO: allow overriding the default storage\n const storage = new IpfsStorage();\n\n const pkg = require(\"../../package.json\");\n\n const cliVersion = pkg.version;\n\n //yes this has to look like this, eliminates whitespace\n console.info(`\n $$\\\\ $$\\\\ $$\\\\ $$\\\\ $$\\\\ \n $$ | $$ | \\\\__| $$ | $$ | \n$$$$$$\\\\ $$$$$$$\\\\ $$\\\\ $$$$$$\\\\ $$$$$$$ |$$\\\\ $$\\\\ $$\\\\ $$$$$$\\\\ $$$$$$$\\\\ \n\\\\_$$ _| $$ __$$\\\\ $$ |$$ __$$\\\\ $$ __$$ |$$ | $$ | $$ |$$ __$$\\\\ $$ __$$\\\\ \n $$ | $$ | $$ |$$ |$$ | \\\\__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |\n $$ |$$\\\\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |\n \\\\$$$$ |$$ | $$ |$$ |$$ | \\\\$$$$$$$ |\\\\$$$$$\\\\$$$$ |\\\\$$$$$$$\\\\ $$$$$$$ |\n \\\\____/ \\\\__| \\\\__|\\\\__|\\\\__| \\\\_______| \\\\_____\\\\____/ \\\\_______|\\\\_______/ `);\n console.info(`\\n 💎 thirdweb-cli v${cliVersion} 💎\\n`);\n updateNotifier({\n pkg,\n shouldNotifyInNpmScript: true,\n //check every time while we're still building the CLI\n updateCheckInterval: 0,\n }).notify();\n\n program\n .name(\"thirdweb-cli\")\n .description(\"Official thirdweb command line interface\")\n .version(cliVersion, \"-v, --version\", \"output the current version\");\n\n program\n .command(\"publish\")\n .description(\"Compile & publish a project\")\n .option(\"-p, --path <project-path>\", \"path to project\", \".\")\n .option(\"--dry-run\", \"dry run (skip actually publishing)\")\n .option(\"-c, --clean\", \"clean artifacts before compiling\")\n .option(\"-d, --debug\", \"show debug logs\")\n .action(async (options) => {\n logger.setSettings({\n minLevel: options.debug ? \"debug\" : \"info\",\n });\n\n let projectPath = process.cwd();\n if (options.path) {\n logger.debug(\"Overriding project path to \" + options.path);\n\n const resolvedPath = (options.path as string).startsWith(\"/\")\n ? options.path\n : path.resolve(`${projectPath}/${options.path}`);\n projectPath = resolvedPath;\n }\n\n logger.debug(\"Publishing project at path \" + projectPath);\n\n const projectType = await detect(projectPath);\n if (projectType === \"unknown\") {\n logger.error(\"Unable to detect project type\");\n return;\n }\n logger.info(\"Detected project type:\", projectType);\n\n const compiledResult = await build(\n projectPath,\n projectType,\n options.clean\n );\n\n if (compiledResult.contracts.length == 0) {\n logger.error(\n \"No thirdweb contract detected. Extend ThirdwebContract to publish your own contracts.\"\n );\n process.exit(1);\n }\n\n logger.info(\"Project compiled successfully\");\n\n if (options.dryRun) {\n logger.info(\"Dry run, skipping publish\");\n process.exit(0);\n }\n\n logger.info(\"Uploading contract data...\");\n const bytecodes = compiledResult.contracts.map((c) => c.bytecode);\n const abis = compiledResult.contracts.map((c) => JSON.stringify(c.abi));\n\n const { metadataUris: bytecodeURIs } = await storage.uploadBatch(\n bytecodes\n );\n const { metadataUris: abiURIs } = await storage.uploadBatch(abis);\n\n const contractMetadatas: string[] = [];\n for (let i = 0; i < compiledResult.contracts.length; i++) {\n const bytecode = bytecodeURIs[i];\n const abi = abiURIs[i];\n const name = compiledResult.contracts[i].name;\n contractMetadatas.push(\n JSON.stringify({\n name: name,\n bytecodeUri: bytecode,\n abiUri: abi,\n } as Contract)\n );\n }\n const { metadataUris: hashes } = await storage.uploadBatch(\n contractMetadatas\n );\n\n logger.info(\"Upload successful\");\n\n const url = new URL(THIRDWEB_URL + \"/contracts/publish\");\n\n for (let hash of hashes) {\n url.searchParams.append(\"ipfs\", hash.replace(\"ipfs://\", \"\"));\n }\n\n logger.info(`Go to this link to publish your contracts:\\n\\n${url}\\n\\n`);\n\n open(url.toString());\n });\n\n await program.parseAsync();\n};\n\nmain()\n .then(() => {\n process.exit(0);\n })\n .catch((err) => {\n logger.error(err);\n process.exit(1);\n });\n","import { existsSync } from \"fs\";\nimport { logger } from \"../helpers/logger\";\nimport { ProjectType } from \"../types/ProjectType\";\nimport { Detector } from \"./detector\";\n\nexport default class FoundryDetector implements Detector {\n public projectType: ProjectType = \"foundry\";\n\n public async matches(path: string): Promise<boolean> {\n logger.debug(\"Checking if \" + path + \" is a Foundry project\");\n return existsSync(path + \"/foundry.toml\");\n }\n}\n","import { Logger } from \"tslog\";\n\nexport const logger = new Logger({\n minLevel: \"info\",\n displayFilePath: \"hidden\",\n displayFunctionName: false,\n displayLoggerName: false,\n});\n","import { existsSync } from \"fs\";\nimport { logger } from \"../helpers/logger\";\nimport { ProjectType } from \"../types/ProjectType\";\nimport { Detector } from \"./detector\";\n\nexport default class HardhatDetector implements Detector {\n public projectType: ProjectType = \"hardhat\";\n\n public async matches(path: string): Promise<boolean> {\n logger.debug(\"Checking if \" + path + \" is a Hardhat project\");\n return (\n existsSync(path + \"/hardhat.config.js\") ||\n existsSync(path + \"/hardhat.config.ts\")\n );\n }\n}\n","import { ProjectType } from \"../types/ProjectType\";\nimport { Detector } from \"./detector\";\nimport FoundryDetector from \"./foundry\";\nimport HardhatDetector from \"./hardhat\";\n\nexport default async function detect(path: string): Promise<ProjectType> {\n const detectors: Detector[] = [new HardhatDetector(), new FoundryDetector()];\n\n for (const detector of detectors) {\n if (await detector.matches(path)) {\n return detector.projectType;\n }\n }\n\n return \"unknown\";\n}\n","import { execSync } from \"child_process\";\nimport { readFileSync } from \"fs\";\nimport { basename, join } from \"path\";\nimport { logger } from \"../helpers/logger\";\nimport { CompileOptions } from \"../interfaces/Builder\";\nimport { ContractPayload } from \"../interfaces/ContractPayload\";\n\nimport { BaseBuilder } from \"./builder-base\";\n\nexport class FoundryBuilder extends BaseBuilder {\n public async compile(options: CompileOptions): Promise<{\n contracts: ContractPayload[];\n }> {\n if (options.clean) {\n logger.info(\"Running forge clean\");\n execSync(\"forge clean\");\n }\n\n logger.info(\"Compiling...\");\n execSync(\"forge build\");\n\n // get the current config first\n const foundryConfig = execSync(\"forge config --json\").toString();\n\n const actualFoundryConfig = JSON.parse(foundryConfig);\n\n const outPath = join(options.projectPath, actualFoundryConfig.out);\n // const contractsPath =\n\n const contracts: ContractPayload[] = [];\n const files: string[] = [];\n this.findFiles(outPath, /^.*(?<!dbg)\\.json$/, files);\n\n for (const file of files) {\n logger.debug(\"Processing:\", file.replace(outPath, \"\"));\n const contractName = basename(file, \".json\");\n const contractJsonFile = readFileSync(file, \"utf-8\");\n\n const contractInfo = JSON.parse(contractJsonFile);\n const abi = contractInfo.abi;\n const bytecode = contractInfo.bytecode.object;\n\n for (const input of abi) {\n if (this.isThirdwebContract(input)) {\n if (contracts.find((c) => c.name === contractName)) {\n logger.error(\n `Found multiple contracts with name \"${contractName}\". Contract names should be unique.`\n );\n process.exit(1);\n }\n contracts.push({\n abi,\n bytecode,\n name: contractName,\n });\n break;\n }\n }\n }\n\n logger.info(\n \"Detected thirdweb contracts:\",\n contracts.map((c) => c.name).join(\", \")\n );\n\n return { contracts };\n }\n}\n","import { existsSync, readdirSync, statSync } from \"fs\";\nimport { basename, join } from \"path\";\nimport { CompileOptions, IBuilder } from \"../interfaces/Builder\";\nimport { ContractPayload } from \"../interfaces/ContractPayload\";\n\nexport abstract class BaseBuilder implements IBuilder {\n abstract compile(\n options: CompileOptions\n ): Promise<{ contracts: ContractPayload[] }>;\n\n protected isThirdwebContract(input: any): boolean {\n try {\n return (\n input.name === \"setThirdwebInfo\" &&\n input.inputs[0].internalType === \"struct ThirdwebContract.ThirdwebInfo\"\n );\n } catch (e) {\n return false;\n }\n }\n\n protected findFiles(startPath: string, filter: RegExp, results: string[]) {\n if (!existsSync(startPath)) {\n console.log(\"no dir \", startPath);\n return;\n }\n\n var files = readdirSync(startPath);\n for (var i = 0; i < files.length; i++) {\n var filename = join(startPath, files[i]);\n //skip the actual thirdweb contract itself\n if (basename(filename, \".json\") === \"ThirdwebContract\") {\n continue;\n }\n var stat = statSync(filename);\n if (stat.isDirectory()) {\n this.findFiles(filename, filter, results);\n } else if (filter.test(filename)) {\n results.push(filename);\n }\n }\n }\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { HardhatConfig } from \"hardhat/types\";\nimport { basename, join, resolve } from \"path\";\nimport { logger } from \"../helpers/logger\";\nimport { CompileOptions } from \"../interfaces/Builder\";\nimport { ContractPayload } from \"../interfaces/ContractPayload\";\nimport { execSync } from \"child_process\";\nimport { BaseBuilder } from \"./builder-base\";\n\nexport class HardhatBuilder extends BaseBuilder {\n public async compile(options: CompileOptions): Promise<{\n contracts: ContractPayload[];\n }> {\n if (options.clean) {\n logger.info(\"Running hardhat clean\");\n execSync(\"npx hardhat clean\");\n }\n\n logger.info(\"Compiling...\");\n execSync(\"npx hardhat compile\");\n //we get our very own extractor script from the dir that we're in during execution\n // this is `./dist/cli` (for all purposes of the CLI)\n // then we look up the hardhat config extractor file path from there\n const configExtractorScriptPath = resolve(\n __dirname,\n \"../helpers/hardhat-config-extractor.js\"\n );\n\n //the hardhat extractor **logs out** the runtime config of hardhat, we take that stdout and parse it\n const stringifiedConfig = execSync(\n `npx hardhat run ${configExtractorScriptPath} --no-compile`\n ).toString();\n //voila the hardhat config\n const actualHardhatConfig = JSON.parse(stringifiedConfig) as HardhatConfig;\n\n logger.debug(\n \"successfully extracted hardhat config\",\n actualHardhatConfig.paths\n );\n\n const artifactsPath = actualHardhatConfig.paths.artifacts;\n const sourcesDir = actualHardhatConfig.paths.sources.replace(\n options.projectPath,\n \"\"\n );\n const contractsPath = join(artifactsPath, sourcesDir);\n\n const contracts: ContractPayload[] = [];\n const files: string[] = [];\n this.findFiles(contractsPath, /^.*(?<!dbg)\\.json$/, files);\n\n for (const file of files) {\n logger.debug(\"Processing:\", file.replace(contractsPath, \"\"));\n const contractName = basename(file, \".json\");\n const contractJsonFile = readFileSync(file, \"utf-8\");\n\n const contractInfo = JSON.parse(contractJsonFile);\n const abi = contractInfo.abi;\n const bytecode = contractInfo.bytecode;\n\n for (const input of abi) {\n if (this.isThirdwebContract(input)) {\n if (contracts.find((c) => c.name === contractName)) {\n logger.error(\n `Found multiple contracts with name \"${contractName}\". Contract names should be unique.`\n );\n process.exit(1);\n }\n contracts.push({\n abi,\n bytecode,\n name: contractName,\n });\n break;\n }\n }\n }\n\n logger.info(\n \"Detected thirdweb contracts:\",\n contracts.map((c) => c.name).join(\", \")\n );\n\n return {\n contracts,\n };\n }\n}\n","import { ContractPayload } from \"../interfaces/ContractPayload\";\nimport { ProjectType } from \"./../types/ProjectType\";\nimport { FoundryBuilder } from \"./foundry\";\nimport { HardhatBuilder } from \"./hardhat\";\n\nexport default async function build(\n path: string,\n projectType: ProjectType,\n clean: boolean\n): Promise<{\n contracts: ContractPayload[];\n}> {\n switch (projectType) {\n case \"hardhat\": {\n const builder = new HardhatBuilder();\n return await builder.compile({\n name: \"\",\n projectPath: path,\n clean,\n });\n }\n\n case \"foundry\": {\n const builder = new FoundryBuilder();\n return await builder.compile({\n name: \"\",\n projectPath: path,\n clean,\n });\n }\n\n default: {\n throw new Error(\"Unknown project type\");\n }\n }\n}\n"],"mappings":"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","names":[]}
|
1
|
+
{"version":3,"sources":["../../src/constants/urls.ts","../../src/core/helpers/logger.ts","../../src/core/builder/builder-base.ts","../../src/core/builder/brownie.ts","../../src/core/builder/foundry.ts","../../src/core/builder/hardhat.ts","../../src/core/builder/truffle.ts","../../src/core/builder/build.ts","../../src/core/detection/brownie.ts","../../src/core/detection/foundry.ts","../../src/core/detection/hardhat.ts","../../src/core/detection/truffle.ts","../../src/core/detection/detect.ts","../../src/common/error.ts","../../src/core/helpers/storage.ts","../../src/core/storage/ipfs-storage.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * @internal\n */\nexport const DEFAULT_IPFS_GATEWAY = \"https://cloudflare-ipfs.com/ipfs/\";\n\n/**\n * @internal\n */\nexport const TW_IPFS_SERVER_URL = \"https://upload.nftlabs.co\";\n\n/**\n * @internal\n */\nexport const PINATA_IPFS_URL = `https://api.pinata.cloud/pinning/pinFileToIPFS`;\n\n/**\n * @internal\n */\nexport const THIRDWEB_URL = `https://nightly.thirdweb.com`;\n","import { Logger } from \"tslog\";\n\nexport const logger = new Logger({\n minLevel: \"info\",\n displayFilePath: \"hidden\",\n displayFunctionName: false,\n displayLoggerName: false,\n});\n","import { logger } from \"../helpers/logger\";\nimport { CompileOptions, IBuilder } from \"../interfaces/Builder\";\nimport { ContractPayload } from \"../interfaces/ContractPayload\";\nimport { existsSync, readdirSync, statSync } from \"fs\";\nimport { basename, join } from \"path\";\n\nexport abstract class BaseBuilder implements IBuilder {\n abstract compile(\n options: CompileOptions,\n ): Promise<{ contracts: ContractPayload[] }>;\n\n protected isThirdwebContract(input: any): boolean {\n try {\n return (\n input.name === \"setThirdwebInfo\" &&\n input.inputs[0].internalType === \"struct ThirdwebContract.ThirdwebInfo\"\n );\n } catch (e) {\n return false;\n }\n }\n\n protected findFiles(startPath: string, filter: RegExp, results: string[]) {\n if (!existsSync(startPath)) {\n console.log(\"no dir \", startPath);\n return;\n }\n\n const files = readdirSync(startPath);\n for (let i = 0; i < files.length; i++) {\n const filename = join(startPath, files[i]);\n //skip the actual thirdweb contract itself\n if (basename(filename, \".json\") === \"ThirdwebContract\") {\n continue;\n }\n const stat = statSync(filename);\n\n // brownie has a \"depdendencies\" directory *inside* the build directory, if we detect that we should skip it\n if (stat.isDirectory() && basename(filename) === \"dependencies\") {\n logger.debug('skipping \"dependencies\" directory');\n continue;\n }\n if (stat.isDirectory()) {\n this.findFiles(filename, filter, results);\n } else if (filter.test(filename)) {\n results.push(filename);\n }\n }\n }\n}\n","import { logger } from \"../helpers/logger\";\nimport { CompileOptions } from \"../interfaces/Builder\";\nimport { ContractPayload } from \"../interfaces/ContractPayload\";\nimport { BaseBuilder } from \"./builder-base\";\nimport { execSync } from \"child_process\";\nimport { existsSync, readFileSync, rmdirSync } from \"fs\";\nimport { basename, join } from \"path\";\nimport { parse } from \"yaml\";\n\nexport class BrownieBuilder extends BaseBuilder {\n public async compile(options: CompileOptions): Promise<{\n contracts: ContractPayload[];\n }> {\n const config = parse(\n readFileSync(join(options.projectPath, \"brownie-config.yaml\"), \"utf-8\"),\n );\n\n const buildPath = join(\n options.projectPath,\n config?.project_structure?.build || \"./build\",\n );\n\n if (options.clean) {\n logger.info(\"Cleaning build directory\");\n existsSync(buildPath) && rmdirSync(buildPath, { recursive: true });\n }\n\n logger.info(\"Compiling...\");\n execSync(\"brownie compile\");\n\n const contractsPath = join(buildPath, \"contracts/\");\n\n const contracts: ContractPayload[] = [];\n const files: string[] = [];\n this.findFiles(contractsPath, /^.*(?<!dbg)\\.json$/, files);\n\n for (const file of files) {\n logger.debug(\"Processing:\", file.replace(contractsPath, \"\"));\n const contractName = basename(file, \".json\");\n const contractJsonFile = readFileSync(file, \"utf-8\");\n\n const contractInfo = JSON.parse(contractJsonFile);\n const abi = contractInfo.abi;\n const bytecode = contractInfo.bytecode;\n\n for (const input of abi) {\n if (this.isThirdwebContract(input)) {\n if (contracts.find((c) => c.name === contractName)) {\n logger.error(\n `Found multiple contracts with name \"${contractName}\". Contract names should be unique.`,\n );\n process.exit(1);\n }\n contracts.push({\n abi,\n bytecode,\n name: contractName,\n });\n break;\n }\n }\n }\n\n return { contracts };\n }\n}\n","import { logger } from \"../helpers/logger\";\nimport { CompileOptions } from \"../interfaces/Builder\";\nimport { ContractPayload } from \"../interfaces/ContractPayload\";\nimport { BaseBuilder } from \"./builder-base\";\nimport { execSync } from \"child_process\";\nimport { readFileSync } from \"fs\";\nimport { basename, join } from \"path\";\n\nexport class FoundryBuilder extends BaseBuilder {\n public async compile(options: CompileOptions): Promise<{\n contracts: ContractPayload[];\n }> {\n if (options.clean) {\n logger.info(\"Running forge clean\");\n execSync(\"forge clean\");\n }\n\n logger.info(\"Compiling...\");\n execSync(\"forge build\");\n\n // get the current config first\n const foundryConfig = execSync(\"forge config --json\").toString();\n\n const actualFoundryConfig = JSON.parse(foundryConfig);\n\n const outPath = join(options.projectPath, actualFoundryConfig.out);\n // const contractsPath =\n\n const contracts: ContractPayload[] = [];\n const files: string[] = [];\n this.findFiles(outPath, /^.*(?<!dbg)\\.json$/, files);\n\n for (const file of files) {\n logger.debug(\"Processing:\", file.replace(outPath, \"\"));\n const contractName = basename(file, \".json\");\n const contractJsonFile = readFileSync(file, \"utf-8\");\n\n const contractInfo = JSON.parse(contractJsonFile);\n const abi = contractInfo.abi;\n const bytecode = contractInfo.bytecode.object;\n\n for (const input of abi) {\n if (this.isThirdwebContract(input)) {\n if (contracts.find((c) => c.name === contractName)) {\n logger.error(\n `Found multiple contracts with name \"${contractName}\". Contract names should be unique.`,\n );\n process.exit(1);\n }\n contracts.push({\n abi,\n bytecode,\n name: contractName,\n });\n break;\n }\n }\n }\n\n return { contracts };\n }\n}\n","import { logger } from \"../helpers/logger\";\nimport { CompileOptions } from \"../interfaces/Builder\";\nimport { ContractPayload } from \"../interfaces/ContractPayload\";\nimport { BaseBuilder } from \"./builder-base\";\nimport { execSync } from \"child_process\";\nimport { existsSync, readFileSync, readdirSync, statSync } from \"fs\";\nimport { HardhatConfig } from \"hardhat/types\";\nimport { basename, join, resolve } from \"path\";\n\nexport class HardhatBuilder extends BaseBuilder {\n public async compile(options: CompileOptions): Promise<{\n contracts: ContractPayload[];\n }> {\n if (options.clean) {\n logger.info(\"Running hardhat clean\");\n execSync(\"npx hardhat clean\");\n }\n\n logger.info(\"Compiling...\");\n execSync(\"npx hardhat compile\");\n //we get our very own extractor script from the dir that we're in during execution\n // this is `./dist/cli` (for all purposes of the CLI)\n // then we look up the hardhat config extractor file path from there\n const configExtractorScriptPath = resolve(\n __dirname,\n \"../helpers/hardhat-config-extractor.js\",\n );\n\n //the hardhat extractor **logs out** the runtime config of hardhat, we take that stdout and parse it\n const stringifiedConfig = execSync(\n `npx hardhat run ${configExtractorScriptPath} --no-compile`,\n ).toString();\n //voila the hardhat config\n const actualHardhatConfig = JSON.parse(stringifiedConfig) as HardhatConfig;\n\n logger.debug(\n \"successfully extracted hardhat config\",\n actualHardhatConfig.paths,\n );\n\n const artifactsPath = actualHardhatConfig.paths.artifacts;\n const sourcesDir = actualHardhatConfig.paths.sources.replace(\n options.projectPath,\n \"\",\n );\n const contractsPath = join(artifactsPath, sourcesDir);\n\n const contracts: ContractPayload[] = [];\n const files: string[] = [];\n this.findFiles(contractsPath, /^.*(?<!dbg)\\.json$/, files);\n\n for (const file of files) {\n logger.debug(\"Processing:\", file.replace(contractsPath, \"\"));\n const contractName = basename(file, \".json\");\n const contractJsonFile = readFileSync(file, \"utf-8\");\n\n const contractInfo = JSON.parse(contractJsonFile);\n const abi = contractInfo.abi;\n const bytecode = contractInfo.bytecode;\n\n for (const input of abi) {\n if (this.isThirdwebContract(input)) {\n if (contracts.find((c) => c.name === contractName)) {\n logger.error(\n `Found multiple contracts with name \"${contractName}\". Contract names should be unique.`,\n );\n process.exit(1);\n }\n contracts.push({\n abi,\n bytecode,\n name: contractName,\n });\n break;\n }\n }\n }\n\n return {\n contracts,\n };\n }\n}\n","import { logger } from \"../helpers/logger\";\nimport { CompileOptions } from \"../interfaces/Builder\";\nimport { ContractPayload } from \"../interfaces/ContractPayload\";\nimport { BaseBuilder } from \"./builder-base\";\nimport { execSync } from \"child_process\";\nimport { existsSync, readFileSync, rmdirSync } from \"fs\";\nimport { basename, join } from \"path\";\n\nexport class TruffleBuilder extends BaseBuilder {\n public async compile(options: CompileOptions): Promise<{\n contracts: ContractPayload[];\n }> {\n // get the current config first\n const truffleConfig = require(join(\n options.projectPath,\n \"truffle-config.js\",\n ));\n\n const buildPath = join(\n options.projectPath,\n truffleConfig.contracts_build_directory || \"./build/contracts\",\n );\n\n if (options.clean) {\n logger.info(\"Cleaning build directory\");\n existsSync(buildPath) && rmdirSync(buildPath, { recursive: true });\n }\n\n logger.info(\"Compiling...\");\n execSync(\"npx truffle compile\");\n\n const contracts: ContractPayload[] = [];\n const files: string[] = [];\n this.findFiles(buildPath, /^.*(?<!dbg)\\.json$/, files);\n\n for (const file of files) {\n logger.debug(\"Processing:\", file.replace(buildPath, \"\"));\n const contractName = basename(file, \".json\");\n const contractJsonFile = readFileSync(file, \"utf-8\");\n\n const contractInfo = JSON.parse(contractJsonFile);\n const abi = contractInfo.abi;\n const bytecode = contractInfo.bytecode;\n\n for (const input of abi) {\n if (this.isThirdwebContract(input)) {\n if (contracts.find((c) => c.name === contractName)) {\n logger.error(\n `Found multiple contracts with name \"${contractName}\". Contract names should be unique.`,\n );\n process.exit(1);\n }\n contracts.push({\n abi,\n bytecode,\n name: contractName,\n });\n break;\n }\n }\n }\n\n return { contracts };\n }\n}\n","import { ContractPayload } from \"../interfaces/ContractPayload\";\nimport { ProjectType } from \"./../types/ProjectType\";\nimport { BrownieBuilder } from \"./brownie\";\nimport { FoundryBuilder } from \"./foundry\";\nimport { HardhatBuilder } from \"./hardhat\";\nimport { TruffleBuilder } from \"./truffle\";\n\nexport default async function build(\n path: string,\n projectType: ProjectType,\n clean: boolean,\n): Promise<{\n contracts: ContractPayload[];\n}> {\n switch (projectType) {\n case \"hardhat\": {\n const builder = new HardhatBuilder();\n return await builder.compile({\n name: \"\",\n projectPath: path,\n clean,\n });\n }\n\n case \"foundry\": {\n const builder = new FoundryBuilder();\n return await builder.compile({\n name: \"\",\n projectPath: path,\n clean,\n });\n }\n\n case \"truffle\": {\n const builder = new TruffleBuilder();\n return await builder.compile({\n name: \"\",\n projectPath: path,\n clean,\n });\n }\n\n case \"brownie\": {\n const builder = new BrownieBuilder();\n return await builder.compile({\n name: \"\",\n projectPath: path,\n clean,\n });\n }\n\n default: {\n throw new Error(\"Unknown project type\");\n }\n }\n}\n","import { logger } from \"../helpers/logger\";\nimport { ProjectType } from \"../types/ProjectType\";\nimport { Detector } from \"./detector\";\nimport { existsSync } from \"fs\";\n\nexport default class BrownieDetector implements Detector {\n public projectType: ProjectType = \"brownie\";\n\n public matches(path: string): boolean {\n logger.debug(\"Checking if \" + path + \" is a Foundry project\");\n return existsSync(path + \"/brownie-config.yaml\");\n }\n}\n","import { logger } from \"../helpers/logger\";\nimport { ProjectType } from \"../types/ProjectType\";\nimport { Detector } from \"./detector\";\nimport { existsSync } from \"fs\";\n\nexport default class FoundryDetector implements Detector {\n public projectType: ProjectType = \"foundry\";\n\n public matches(path: string): boolean {\n logger.debug(\"Checking if \" + path + \" is a Foundry project\");\n return existsSync(path + \"/foundry.toml\");\n }\n}\n","import { logger } from \"../helpers/logger\";\nimport { ProjectType } from \"../types/ProjectType\";\nimport { Detector } from \"./detector\";\nimport { existsSync } from \"fs\";\n\nexport default class HardhatDetector implements Detector {\n public projectType: ProjectType = \"hardhat\";\n\n public matches(path: string): boolean {\n logger.debug(\"Checking if \" + path + \" is a Hardhat project\");\n return (\n existsSync(path + \"/hardhat.config.js\") ||\n existsSync(path + \"/hardhat.config.ts\")\n );\n }\n}\n","import { logger } from \"../helpers/logger\";\nimport { ProjectType } from \"../types/ProjectType\";\nimport { Detector } from \"./detector\";\nimport { existsSync } from \"fs\";\n\nexport default class TruffleDetector implements Detector {\n public projectType: ProjectType = \"truffle\" as const;\n\n public matches(path: string): boolean {\n logger.debug(\"Checking if \" + path + \" is a Truffle project\");\n return existsSync(path + \"/truffle-config.js\");\n }\n}\n","import { logger } from \"../helpers/logger\";\nimport { ProjectType } from \"../types/ProjectType\";\nimport BrownieDetector from \"./brownie\";\nimport { Detector } from \"./detector\";\nimport FoundryDetector from \"./foundry\";\nimport HardhatDetector from \"./hardhat\";\nimport TruffleDetector from \"./truffle\";\nimport inquirer from \"inquirer\";\n\nexport default async function detect(path: string): Promise<ProjectType> {\n const detectors: Detector[] = [\n new HardhatDetector(),\n new FoundryDetector(),\n new TruffleDetector(),\n new BrownieDetector(),\n ];\n\n const possibleProjectTypes = detectors\n .filter((detector) => detector.matches(path))\n .map((detector) => detector.projectType);\n\n //if there is no project returned at all then just return unknown}\n if (!possibleProjectTypes.length) {\n return \"unknown\";\n }\n //if there is only one possible option just return it\n if (possibleProjectTypes.length === 1) {\n logger.info(\"Detected project type:\", possibleProjectTypes[0]);\n return possibleProjectTypes[0];\n }\n\n logger.info(\n \"Detected multiple possible build tools:\",\n possibleProjectTypes.map((s) => `\"${s}\"`).join(\", \"),\n );\n\n const question = \"How would you like to compile your contracts\";\n\n const answer = await inquirer.prompt({\n type: \"list\",\n choices: possibleProjectTypes,\n name: question,\n });\n\n return answer[question];\n}\n","/**\n * @internal\n */\nexport class UploadError extends Error {\n /** @internal */\n constructor(message: string) {\n super(`UPLOAD_FAILED: ${message}`);\n }\n}\n\n/**\n * @internal\n */\nexport class DuplicateFileNameError extends Error {\n /** @internal */\n constructor(fileName: string) {\n super(\n `DUPLICATE_FILE_NAME_ERROR: File name ${fileName} was passed for more than one file.`,\n );\n }\n}\n\n/**\n * Thrown when data fails to fetch from storage.\n * @internal\n */\nexport class FetchError extends Error {\n public innerError?: Error;\n\n /** @internal */\n constructor(message: string, innerError?: Error) {\n super(`FETCH_FAILED: ${message}`);\n this.innerError = innerError;\n }\n}\n","import { Json } from \"../types\";\n\n/**\n * Given a map of file hashes to ipfs uris, this function will hash\n * all properties recursively and replace them with the ipfs uris\n * from the map passed in. If a hash is missing from the map, the function\n * will throw an error.\n *\n * @internal\n *\n * @param object - The object to recursively process\n * @param cids - The array of file hashes to ipfs uris in the recurse order\n * @returns - The processed metadata with properties pointing at ipfs in place of `File | Buffer`\n */\nexport function replaceFilePropertiesWithHashes(\n object: Record<string, any>,\n cids: string[],\n) {\n const keys = Object.keys(object);\n for (const key in keys) {\n const val = object[keys[key]];\n const isFile = val instanceof File || val instanceof Buffer;\n if (typeof val === \"object\" && !isFile) {\n replaceFilePropertiesWithHashes(val, cids);\n continue;\n }\n\n if (!isFile) {\n continue;\n }\n\n object[keys[key]] = `ipfs://${cids.splice(0, 1)[0]}`;\n }\n return object;\n}\n\n/**\n * Replaces all ipfs:// hashes (or any other scheme) with gateway url\n * @param object\n * @param scheme\n * @param gatewayUrl\n */\nexport function replaceHashWithGatewayUrl(\n object: Record<string, any>,\n scheme: string,\n gatewayUrl: string,\n): Record<string, any> {\n const keys = Object.keys(object);\n for (const key in keys) {\n const val = object[keys[key]];\n object[keys[key]] = resolveGatewayUrl(val, scheme, gatewayUrl);\n if (Array.isArray(val)) {\n for (const el of val) {\n replaceHashWithGatewayUrl(el, scheme, gatewayUrl);\n }\n }\n if (typeof val === \"object\") {\n replaceHashWithGatewayUrl(val, scheme, gatewayUrl);\n }\n }\n return object;\n}\n\n/**\n * Resolves the full URL of a file for a given gateway.\n *\n * For example, if the hash of a file is `ipfs://bafkreib3u2u6ir2fsl5nkuwixfsb3l4xehri3psjv5yga4inuzsjunk2sy`, then the URL will be:\n * \"https://cloudflare-ipfs.com/ipfs/bafkreibnwjhx5s3r2rggdoy3hw7lr7wmgy4bas35oky3ed6eijklk2oyvq\"\n * if the gateway is `cloudflare-ipfs.com`.\n *\n * @param ipfsHash\n * @param scheme\n * @param gatewayUrl\n */\nexport function resolveGatewayUrl<T extends Json>(\n ipfsHash: T,\n scheme: string,\n gatewayUrl: string,\n): T {\n if (typeof ipfsHash === \"string\") {\n return ipfsHash && ipfsHash.toLowerCase().includes(scheme)\n ? (ipfsHash.replace(scheme, gatewayUrl) as T)\n : ipfsHash;\n } else {\n return ipfsHash;\n }\n}\n","import {\n DuplicateFileNameError,\n FetchError,\n UploadError,\n} from \"../../common/error\";\nimport {\n DEFAULT_IPFS_GATEWAY,\n PINATA_IPFS_URL,\n TW_IPFS_SERVER_URL,\n} from \"../../constants/urls\";\nimport {\n replaceFilePropertiesWithHashes,\n replaceHashWithGatewayUrl,\n resolveGatewayUrl,\n} from \"../helpers/storage\";\nimport { IStorage } from \"../interfaces/IStorage\";\nimport { FileOrBuffer, JsonObject } from \"../types\";\n\nconst orig = process.emitWarning;\n//suppress warnings whule we require a bunch of stuff\nprocess.emitWarning = () => {};\nrequire(\"isomorphic-fetch\");\n\nif (!globalThis.FormData) {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n globalThis.FormData = require(\"form-data\");\n}\n\nif (!globalThis.File) {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n globalThis.File = require(\"@web-std/file\").File;\n}\n\n//re-enable warnings\nprocess.emitWarning = orig;\n\n/**\n * @internal\n */\ninterface CidWithFileName {\n // base cid of the directory\n cid: string;\n\n // file name of the file without cid\n fileNames: string[];\n}\n\n/**\n * IPFS Storage implementation, accepts custom IPFS gateways\n * @public\n */\nexport class IpfsStorage implements IStorage {\n private gatewayUrl: string;\n\n constructor(gatewayUrl: string = DEFAULT_IPFS_GATEWAY) {\n this.gatewayUrl = `${gatewayUrl.replace(/\\/$/, \"\")}/`;\n }\n\n /**\n * {@inheritDoc IStorage.upload}\n */\n public async upload(\n data: string | FileOrBuffer,\n contractAddress?: string,\n signerAddress?: string,\n ): Promise<string> {\n const cid = await this.uploadBatch(\n [data],\n 0,\n contractAddress,\n signerAddress,\n );\n return `${cid}0`;\n }\n\n /**\n * {@inheritDoc IStorage.uploadBatch}\n */\n public async uploadBatch(\n files: (string | FileOrBuffer)[],\n fileStartNumber = 0,\n contractAddress?: string,\n signerAddress?: string,\n ) {\n const { cid, fileNames } = await this.uploadBatchWithCid(\n files,\n fileStartNumber,\n contractAddress,\n signerAddress,\n );\n\n const baseUri = `ipfs://${cid}/`;\n const uris = fileNames.map((filename) => `${baseUri}${filename}`);\n\n return {\n baseUri,\n metadataUris: uris,\n };\n }\n\n /**\n * {@inheritDoc IStorage.getUploadToken}\n */\n public async getUploadToken(contractAddress: string): Promise<string> {\n const headers = {\n \"X-App-Name\": `CONSOLE-TS-SDK-${contractAddress}`,\n };\n const res = await fetch(`${TW_IPFS_SERVER_URL}/grant`, {\n method: \"GET\",\n headers,\n });\n if (!res.ok) {\n throw new FetchError(`Failed to get upload token`);\n }\n const body = await res.text();\n return body;\n }\n\n /**\n * {@inheritDoc IStorage.get}\n */\n public async get(hash: string): Promise<Record<string, any>> {\n const res = await this._get(hash);\n const json = await res.json();\n return replaceHashWithGatewayUrl(json, \"ipfs://\", this.gatewayUrl);\n }\n\n /**\n * {@inheritDoc IStorage.uploadMetadata}\n */\n public async uploadMetadata(\n metadata: JsonObject,\n contractAddress?: string,\n signerAddress?: string,\n ): Promise<string> {\n // since there's only single object, always use the first index\n const { metadataUris } = await this.uploadMetadataBatch(\n [metadata],\n 0,\n contractAddress,\n signerAddress,\n );\n return metadataUris[0];\n }\n\n /**\n * {@inheritDoc IStorage.uploadMetadataBatch}\n */\n public async uploadMetadataBatch(\n metadatas: JsonObject[],\n fileStartNumber?: number,\n contractAddress?: string,\n signerAddress?: string,\n ) {\n const metadataToUpload = (await this.batchUploadProperties(metadatas)).map(\n (m: any) => JSON.stringify(m),\n );\n\n const { cid, fileNames } = await this.uploadBatchWithCid(\n metadataToUpload,\n fileStartNumber,\n contractAddress,\n signerAddress,\n );\n\n const baseUri = `ipfs://${cid}/`;\n const uris = fileNames.map((filename) => `${baseUri}${filename}`);\n\n return {\n baseUri,\n metadataUris: uris,\n };\n }\n\n /** *************************\n * PRIVATE FUNCTIONS\n *************************/\n\n private async _get(hash: string): Promise<Response> {\n let uri = hash;\n if (hash) {\n uri = resolveGatewayUrl(hash, \"ipfs://\", this.gatewayUrl);\n }\n const result = await fetch(uri);\n if (!result.ok) {\n throw new Error(`Status code (!= 200) =${result.status}`);\n }\n return result;\n }\n\n /**\n * Pre-processes metadata and uploads all file properties\n * to storage in *bulk*, then performs a string replacement of\n * all file properties -\\> the resulting ipfs uri. This is\n * called internally by `uploadMetadataBatch`.\n *\n * @internal\n *\n * @param metadata - The metadata to recursively process\n * @returns - The processed metadata with properties pointing at ipfs in place of `File | Buffer`\n */\n private async batchUploadProperties(metadatas: JsonObject[]) {\n const filesToUpload = metadatas.flatMap((m) =>\n this.buildFilePropertiesMap(m, []),\n );\n if (filesToUpload.length === 0) {\n return metadatas;\n }\n const { cid, fileNames } = await this.uploadBatchWithCid(filesToUpload);\n\n const cids = [];\n // recurse ordered array\n for (const filename of fileNames) {\n cids.push(`${cid}/${filename}`);\n }\n\n const finalMetadata = await replaceFilePropertiesWithHashes(\n metadatas,\n cids,\n );\n return finalMetadata;\n }\n\n /**\n * This function recurisely traverses an object and hashes any\n * `Buffer` or `File` objects into the returned map.\n *\n * @param object - the Json Object\n * @param files - The running array of files or buffer to upload\n * @returns - The final map of all hashes to files\n */\n private buildFilePropertiesMap(\n object: JsonObject,\n files: (File | Buffer)[] = [],\n ): (File | Buffer)[] {\n if (Array.isArray(object)) {\n object.forEach((element) => {\n this.buildFilePropertiesMap(element, files);\n });\n } else if (object) {\n const values = Object.values(object);\n for (const val of values) {\n if (val instanceof File || val instanceof Buffer) {\n files.push(val);\n } else if (typeof val === \"object\") {\n this.buildFilePropertiesMap(val as JsonObject, files);\n }\n }\n }\n return files;\n }\n\n private async uploadBatchWithCid(\n files: (string | FileOrBuffer)[],\n fileStartNumber = 0,\n contractAddress?: string,\n signerAddress?: string,\n ): Promise<CidWithFileName> {\n const token = await this.getUploadToken(contractAddress || \"\");\n const metadata = {\n name: `CONSOLE-TS-SDK-${contractAddress}`,\n keyvalues: {\n sdk: \"typescript\",\n contractAddress,\n signerAddress,\n },\n };\n const data = new FormData();\n const fileNames: string[] = [];\n files.forEach((file, i) => {\n let fileName = \"\";\n let fileData = file;\n // if it is a file, we passthrough the file extensions,\n // if it is a buffer or string, the filename would be fileStartNumber + index\n // if it is a buffer or string with names, the filename would be the name\n if (file instanceof File) {\n let extensions = \"\";\n if (file.name) {\n const extensionStartIndex = file.name.lastIndexOf(\".\");\n if (extensionStartIndex > -1) {\n extensions = file.name.substring(extensionStartIndex);\n }\n }\n fileName = `${i + fileStartNumber}${extensions}`;\n } else if (file instanceof Buffer || typeof file === \"string\") {\n fileName = `${i + fileStartNumber}`;\n } else if (file && file.name && file?.data) {\n fileData = file?.data;\n fileName = `${file.name}`;\n } else {\n // default behavior\n fileName = `${i + fileStartNumber}`;\n }\n\n const filepath = `files/${fileName}`;\n if (fileNames.indexOf(fileName) > -1) {\n throw new DuplicateFileNameError(fileName);\n }\n fileNames.push(fileName);\n if (typeof window === \"undefined\") {\n data.append(\"file\", fileData as any, { filepath } as any);\n } else {\n // browser does blob things, filepath is parsed differently on browser vs node.\n // pls pinata?\n data.append(\"file\", new Blob([fileData as any]), filepath);\n }\n });\n\n data.append(\"pinataMetadata\", JSON.stringify(metadata));\n const res = await fetch(PINATA_IPFS_URL, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n },\n body: data as any,\n });\n const body = await res.json();\n if (!res.ok) {\n console.log(body);\n throw new UploadError(\"Failed to upload files to IPFS\");\n }\n return {\n cid: body.IpfsHash,\n fileNames,\n };\n }\n}\n","#!/usr/bin/env node\nimport { THIRDWEB_URL } from \"../constants/urls\";\nimport build from \"../core/builder/build\";\nimport detect from \"../core/detection/detect\";\nimport { logger } from \"../core/helpers/logger\";\nimport { Contract } from \"../core/interfaces/Contract\";\nimport { IpfsStorage } from \"./../core/storage/ipfs-storage\";\nimport { Command } from \"commander\";\nimport open from \"open\";\nimport path from \"path\";\nimport updateNotifier from \"update-notifier\";\nimport { URL } from \"url\";\n\nconst main = async () => {\n const program = new Command();\n\n // TODO: allow overriding the default storage\n const storage = new IpfsStorage();\n\n const pkg = require(\"../../package.json\");\n\n const cliVersion = pkg.version;\n\n //yes this has to look like this, eliminates whitespace\n console.info(`\n $$\\\\ $$\\\\ $$\\\\ $$\\\\ $$\\\\ \n $$ | $$ | \\\\__| $$ | $$ | \n$$$$$$\\\\ $$$$$$$\\\\ $$\\\\ $$$$$$\\\\ $$$$$$$ |$$\\\\ $$\\\\ $$\\\\ $$$$$$\\\\ $$$$$$$\\\\ \n\\\\_$$ _| $$ __$$\\\\ $$ |$$ __$$\\\\ $$ __$$ |$$ | $$ | $$ |$$ __$$\\\\ $$ __$$\\\\ \n $$ | $$ | $$ |$$ |$$ | \\\\__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |\n $$ |$$\\\\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |\n \\\\$$$$ |$$ | $$ |$$ |$$ | \\\\$$$$$$$ |\\\\$$$$$\\\\$$$$ |\\\\$$$$$$$\\\\ $$$$$$$ |\n \\\\____/ \\\\__| \\\\__|\\\\__|\\\\__| \\\\_______| \\\\_____\\\\____/ \\\\_______|\\\\_______/ `);\n console.info(`\\n 💎 thirdweb-cli v${cliVersion} 💎\\n`);\n updateNotifier({\n pkg,\n shouldNotifyInNpmScript: true,\n //check every time while we're still building the CLI\n updateCheckInterval: 0,\n }).notify();\n\n program\n .name(\"thirdweb-cli\")\n .description(\"Official thirdweb command line interface\")\n .version(cliVersion, \"-v, --version\", \"output the current version\");\n\n program\n .command(\"publish\")\n .description(\"Compile & publish a project\")\n .option(\"-p, --path <project-path>\", \"path to project\", \".\")\n .option(\"--dry-run\", \"dry run (skip actually publishing)\")\n .option(\"-c, --clean\", \"clean artifacts before compiling\")\n .option(\"-d, --debug\", \"show debug logs\")\n .action(async (options) => {\n logger.setSettings({\n minLevel: options.debug ? \"debug\" : \"info\",\n });\n\n let projectPath = process.cwd();\n if (options.path) {\n logger.debug(\"Overriding project path to \" + options.path);\n\n const resolvedPath = (options.path as string).startsWith(\"/\")\n ? options.path\n : path.resolve(`${projectPath}/${options.path}`);\n projectPath = resolvedPath;\n }\n\n logger.debug(\"Publishing project at path \" + projectPath);\n\n const projectType = await detect(projectPath);\n if (projectType === \"unknown\") {\n logger.error(\"Unable to detect project type\");\n process.exit(1);\n }\n\n const compiledResult = await build(\n projectPath,\n projectType,\n options.clean,\n );\n\n if (compiledResult.contracts.length == 0) {\n logger.error(\n \"No thirdweb contract detected. Extend ThirdwebContract to publish your own contracts.\",\n );\n process.exit(1);\n }\n logger.info(\n \"Detected thirdweb contracts:\",\n compiledResult.contracts.map((c) => `\"${c.name}\"`).join(\", \"),\n );\n\n logger.info(\"Project compiled successfully\");\n\n if (options.dryRun) {\n logger.info(\"Dry run, skipping publish\");\n process.exit(0);\n }\n\n logger.info(\"Uploading contract data...\");\n const bytecodes = compiledResult.contracts.map((c) => c.bytecode);\n const abis = compiledResult.contracts.map((c) => JSON.stringify(c.abi));\n\n const { metadataUris: bytecodeURIs } = await storage.uploadBatch(\n bytecodes,\n );\n const { metadataUris: abiURIs } = await storage.uploadBatch(abis);\n\n const contractMetadatas: string[] = [];\n for (let i = 0; i < compiledResult.contracts.length; i++) {\n const bytecode = bytecodeURIs[i];\n const abi = abiURIs[i];\n const name = compiledResult.contracts[i].name;\n contractMetadatas.push(\n JSON.stringify({\n name: name,\n bytecodeUri: bytecode,\n abiUri: abi,\n } as Contract),\n );\n }\n const { metadataUris: hashes } = await storage.uploadBatch(\n contractMetadatas,\n );\n\n logger.info(\"Upload successful\");\n\n const url = new URL(THIRDWEB_URL + \"/contracts/publish\");\n\n for (let hash of hashes) {\n url.searchParams.append(\"ipfs\", hash.replace(\"ipfs://\", \"\"));\n }\n\n logger.info(`Go to this link to publish your contracts:\\n\\n${url}\\n\\n`);\n\n open(url.toString());\n });\n\n await program.parseAsync();\n};\n\nmain()\n .then(() => {\n process.exit(0);\n })\n .catch((err) => {\n logger.error(err);\n process.exit(1);\n });\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
"name": "thirdweb",
|
3
3
|
"main": "dist/cli/index.js",
|
4
4
|
"types": "dist/cli/index.d.ts",
|
5
|
-
"version": "0.
|
5
|
+
"version": "0.3.1",
|
6
6
|
"repository": "git@github.com:thirdweb-dev/thirdweb-cli.git",
|
7
7
|
"author": "sdk@thirdweb.com",
|
8
8
|
"license": "MIT",
|
@@ -10,10 +10,12 @@
|
|
10
10
|
"node": ">=14.0.0 <17"
|
11
11
|
},
|
12
12
|
"devDependencies": {
|
13
|
-
"@
|
13
|
+
"@trivago/prettier-plugin-sort-imports": "^3.2.0",
|
14
|
+
"@types/inquirer": "^8.2.1",
|
14
15
|
"@types/node": "^17.0.23",
|
15
16
|
"@types/update-notifier": "^5.1.0",
|
16
17
|
"hardhat": "^2.9.3",
|
18
|
+
"prettier": "^2.6.2",
|
17
19
|
"ts-node": "^10.7.0",
|
18
20
|
"tsc": "^2.0.4",
|
19
21
|
"tsup": "^5.12.1",
|
@@ -23,15 +25,18 @@
|
|
23
25
|
"@web-std/file": "^3.0.2",
|
24
26
|
"commander": "^9.1.0",
|
25
27
|
"form-data": "^4.0.0",
|
28
|
+
"inquirer": "^8.2.3",
|
26
29
|
"isomorphic-fetch": "^3.0.0",
|
27
30
|
"open": "^8.4.0",
|
28
31
|
"tslog": "^3.3.3",
|
29
|
-
"update-notifier": "^5.1.0"
|
32
|
+
"update-notifier": "^5.1.0",
|
33
|
+
"yaml": "^2.0.1"
|
30
34
|
},
|
31
35
|
"bin": {
|
32
36
|
"thirdweb": "./dist/cli/index.js"
|
33
37
|
},
|
34
38
|
"scripts": {
|
39
|
+
"prettier": "prettier --write 'src/**/*'",
|
35
40
|
"clean": "rm -rf dist/",
|
36
41
|
"cli": "node -r ts-node/register src/cli/index.ts",
|
37
42
|
"build": "yarn clean && tsup --env.NODE_ENV production --minify --format cjs --external hardhat --dts-resolve",
|
package/src/cli/index.ts
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
-
|
2
|
+
import { THIRDWEB_URL } from "../constants/urls";
|
3
|
+
import build from "../core/builder/build";
|
4
|
+
import detect from "../core/detection/detect";
|
5
|
+
import { logger } from "../core/helpers/logger";
|
6
|
+
import { Contract } from "../core/interfaces/Contract";
|
3
7
|
import { IpfsStorage } from "./../core/storage/ipfs-storage";
|
4
8
|
import { Command } from "commander";
|
5
|
-
import path from "path";
|
6
|
-
import detect from "../core/detection/detect";
|
7
|
-
import build from "../core/builder/build";
|
8
|
-
import { THIRDWEB_URL } from "../constants/urls";
|
9
|
-
import { URL } from "url";
|
10
9
|
import open from "open";
|
11
|
-
import
|
12
|
-
import { logger } from "../core/helpers/logger";
|
10
|
+
import path from "path";
|
13
11
|
import updateNotifier from "update-notifier";
|
12
|
+
import { URL } from "url";
|
14
13
|
|
15
14
|
const main = async () => {
|
16
15
|
const program = new Command();
|
@@ -72,22 +71,25 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
|
72
71
|
const projectType = await detect(projectPath);
|
73
72
|
if (projectType === "unknown") {
|
74
73
|
logger.error("Unable to detect project type");
|
75
|
-
|
74
|
+
process.exit(1);
|
76
75
|
}
|
77
|
-
logger.info("Detected project type:", projectType);
|
78
76
|
|
79
77
|
const compiledResult = await build(
|
80
78
|
projectPath,
|
81
79
|
projectType,
|
82
|
-
options.clean
|
80
|
+
options.clean,
|
83
81
|
);
|
84
82
|
|
85
83
|
if (compiledResult.contracts.length == 0) {
|
86
84
|
logger.error(
|
87
|
-
"No thirdweb contract detected. Extend ThirdwebContract to publish your own contracts."
|
85
|
+
"No thirdweb contract detected. Extend ThirdwebContract to publish your own contracts.",
|
88
86
|
);
|
89
87
|
process.exit(1);
|
90
88
|
}
|
89
|
+
logger.info(
|
90
|
+
"Detected thirdweb contracts:",
|
91
|
+
compiledResult.contracts.map((c) => `"${c.name}"`).join(", "),
|
92
|
+
);
|
91
93
|
|
92
94
|
logger.info("Project compiled successfully");
|
93
95
|
|
@@ -101,7 +103,7 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
|
101
103
|
const abis = compiledResult.contracts.map((c) => JSON.stringify(c.abi));
|
102
104
|
|
103
105
|
const { metadataUris: bytecodeURIs } = await storage.uploadBatch(
|
104
|
-
bytecodes
|
106
|
+
bytecodes,
|
105
107
|
);
|
106
108
|
const { metadataUris: abiURIs } = await storage.uploadBatch(abis);
|
107
109
|
|
@@ -115,11 +117,11 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
|
115
117
|
name: name,
|
116
118
|
bytecodeUri: bytecode,
|
117
119
|
abiUri: abi,
|
118
|
-
} as Contract)
|
120
|
+
} as Contract),
|
119
121
|
);
|
120
122
|
}
|
121
123
|
const { metadataUris: hashes } = await storage.uploadBatch(
|
122
|
-
contractMetadatas
|
124
|
+
contractMetadatas,
|
123
125
|
);
|
124
126
|
|
125
127
|
logger.info("Upload successful");
|