import React , { FC , Fragment } from "react" ; import { LogUserApproval , LogInfo , LogError , LogTransactionResult , LogMigrationAborted , AnyLogLine , LogType } from "./LogLineTypes" ; import { DAOMigrationResult , getWeb3 , DAOMigrationCallbacks , migrateDAO , getNetworkName , toDAOMigrationParams , DAOMigrationParams , DAOForm } from "@dorgtech/daocreator-lib" ; import { MDBBtn , MDBIcon , MDBTooltip } from "mdbreact" ; import { STEP } from "../../../commonV2/Stepper" ; import './styles.css' ; interface IProps { migrationStates : any ; } export const DeployButton = ( { migrationStates } ) => { const { installStep , setInstallStep , setNoWeb3Open , setEthSpent , fullLogLines , setFullLogLines , minimalLogLines , setMinimalLogLines , setApproval , result , setResult , alchemyURL , setAlchemyURL , setAborting , failed , setFailed , alchemyAdds , setAlchemyAdds , daoInfo , setDaoInfo , step , form , setLaunching , setDaoLogs , daoLogs } = migrationStates ; const onComplete = ( { arcVersion , name , Avatar , DAOToken , Reputation , Controller } , alchemyURL ) => { setDaoInfo ( [ ... daoInfo , { arcVersion , name , Avatar , DAOToken , Reputation , Controller } ] ) ; setAlchemyAdds ( [ ... alchemyAdds , alchemyURL ] ) ; onStop ( ) ; } ; const onStart = ( ) => { setLaunching ( true ) ; addNewLogs ( ) ; } ; const addMinLogLine = ( log ) => { setMinimalLogLines ( [ ... minimalLogLines , log ] ) ; } ; const addFullLogLine = ( log ) => { setFullLogLines ( [ ... fullLogLines , log ] ) ; onLog ( log . toString ( ) ) ; } ; const onAbort = ( error ) => { console . log ( "onAbort" ) ; console . log ( error ) ; onStop ( ) ; } ; const onLog = ( log ) => { addLog ( log ) ; } ; const onStop = ( ) => { setLaunching ( false ) ; } ; let dao ; if ( step > 2 && form instanceof DAOForm ) { dao = toDAOMigrationParams ( ( form as DAOForm ) . toState ( ) ) ; } const createOrganization = ( ) => { setInstallStep ( STEP . Creating ) ; } ; const configureOrganization = ( ) => { setInstallStep ( STEP . Configuring ) ; } ; const completeOrganization = ( ) => { setInstallStep ( STEP . Completed ) ; } ; const addLog = ( log ) => { setDaoLogs ( ( daoLogs ) => { daoLogs [ daoLogs . length - 1 ] . push ( log ) ; return daoLogs ; } ) ; } ; const addNewLogs = ( ) => { setDaoLogs ( ( daoLogs ) => [ ... daoLogs , [ ] ] ) ; } ; const addLogLine = ( logLine ) => { const { type } = logLine ; addFullLogLine ( logLine ) ; const { UserApproval , Info , Error , TransactionResult , MigrationAborted } = LogType ; console . log ( logLine ) ; switch ( type ) { case UserApproval : const approvalLine = logLine as LogUserApproval ; const { question } = approvalLine ; switch ( question ) { case "About to migrate new DAO. Continue?" : approvalLine . onResponse ( true ) ; console . log ( "Answering true to: " + question ) ; break ; case "We found a deployment that was in progress, pickup where you left off?" : case "We found a deployment that's was in progress, pickup where you left off?" : addMinLogLine ( "Selecting deployment..." ) ; setApproval ( { msg : "Continue previous deployment?" , response : ( res ) : void => { res && configureOrganization ( ) ; setApproval ( undefined ) ; approvalLine . onResponse ( res ) ; } } ) ; break ; default : console . log ( "Unhandled approval log:" ) ; console . log ( question ) ; addMinLogLine ( question ) ; setApproval ( { msg : question , response : ( res ) : void => { setApproval ( undefined ) ; approvalLine . onResponse ( res ) ; } } ) ; break ; } break ; case Info : const infoLine = logLine as LogInfo ; const { info } = infoLine ; switch ( true ) { case info === "Migrating DAO..." : case info . startsWith ( "Using Arc Version:" ) : break ; case info === "Creating a new organization..." : addMinLogLine ( "Signing Create Org Tx..." ) ; break ; case info === "Setting Scheme Registrar parameters..." : addMinLogLine ( "Setting Scheme Registrar params..." ) ; break ; case info === "Setting Generic Scheme parameters..." : addMinLogLine ( "Setting Generic params..." ) ; break ; case info === "Setting Contribution Reward parameters..." : addMinLogLine ( "Setting Contribution Reward params..." ) ; break ; case info === "Setting DAO schemes..." : addMinLogLine ( "Setting DAO schemes..." ) ; break ; case info === "Deploying Controller" : addMinLogLine ( "Deploying Controller..." ) ; break ; case info === "Setting GenesisProtocol parameters..." : addMinLogLine ( "Setting Voting Params..." ) ; break ; case info === "DAO Migration has Finished Successfully!" : completeOrganization ( ) ; break ; default : console . log ( "Unhandled info log:" ) ; console . log ( info ) ; addMinLogLine ( info ) ; break ; } break ; case Error : const errorLine = logLine as LogError ; const { error } = errorLine ; switch ( true ) { case error === "Transaction failed: MetaMask Tx Signature: User denied transaction signature." : break ; case error . startsWith ( 'Provided address "null" is invalid' ) : addMinLogLine ( "Failed to get address" ) ; break ; case error . startsWith ( "Transaction failed: Transaction has been reverted" ) : case error . startsWith ( "Transaction failed: Error" ) : break ; default : console . log ( "Unhandled error log:" ) ; console . log ( error ) ; addMinLogLine ( error ) ; break ; } break ; case TransactionResult : const txLine = logLine as LogTransactionResult ; const { msg } = txLine ; switch ( true ) { case msg === "Created new organization." : configureOrganization ( ) ; break ; case msg . startsWith ( 'Provided address "null" is invalid' ) : addMinLogLine ( "Failed to get address" ) ; break ; case msg === "DAO schemes set." : addMinLogLine ( msg ) ; break ; default : console . log ( "Unhandled txResult log:" ) ; console . log ( msg ) ; break ; } break ; case MigrationAborted : const abortedLine = logLine as LogMigrationAborted ; const abortedMsg = abortedLine . toString ( ) ; setAborting ( true ) ; switch ( true ) { case abortedMsg === "MetaMask Tx Signature: User denied transaction signature." : addMinLogLine ( "Failed to Sign Transaction" ) ; break ; case abortedMsg . startsWith ( "Network request failed" ) : addMinLogLine ( "Network request failed" ) ; break ; case abortedMsg === "Returned values aren't valid, did it run Out of Gas?" : case abortedMsg . startsWith ( "Transaction has been reverted" ) : case abortedMsg . startsWith ( "Error: " ) : addMinLogLine ( "Transaction failed" ) ; break ; default : console . log ( "Unhandled abortedMsg log:" ) ; console . log ( abortedMsg ) ; addMinLogLine ( abortedMsg ) ; break ; } break ; default : console . log ( "Unimplemented log type" ) ; } } ; const getCallbacks = ( ) => { const callbacks = { userApproval : ( msg ) : Promise < boolean > => new Promise < boolean > ( resolve => addLogLine ( new LogUserApproval ( msg , ( resp ) => resolve ( resp ) ) ) ) , info : ( msg ) => addLogLine ( new LogInfo ( msg ) ) , error : ( msg ) => addLogLine ( new LogError ( msg ) ) , txComplete : ( msg , txHash , txCost ) => new Promise < void > ( resolve => { addLogLine ( new LogTransactionResult ( msg , txHash , txCost ) ) ; setEthSpent ( ( ethSpent ) => ( ethSpent += Number ( txCost ) ) ) ; resolve ( ) ; } ) , migrationAborted : ( err ) => { window . onbeforeunload = ( ) => { } ; addLogLine ( new LogMigrationAborted ( err ) ) ; onAbort ( err . toString ( ) ) ; } , migrationComplete : ( result ) => { window . onbeforeunload = ( ) => { } ; setResult ( result ) ; setInstallStep ( STEP . Completed ) ; } , getState : ( ) => { const localState = localStorage . getItem ( "DAO_MIGRATION_STATE" ) ; return localState ? JSON . parse ( localState ) : { } ; } , setState : ( state ) => { localStorage . setItem ( "DAO_MIGRATION_STATE" , JSON . stringify ( state ) ) ; } , cleanState : ( ) => { localStorage . removeItem ( "DAO_MIGRATION_STATE" ) ; } } ; return callbacks ; } ; const startInstallation = async ( ) => { console . log ( "Starting Installation" ) ; console . log ( dao ) ; setNoWeb3Open ( false ) ; setMinimalLogLines ( [ ] ) ; setEthSpent ( 0 ) ; setResult ( undefined ) ; setApproval ( undefined ) ; setFailed ( null ) ; setAlchemyURL ( "" ) ; let web3 = undefined ; try { web3 = await getWeb3 ( ) ; } catch ( e ) { console . log ( e ) ; } if ( ! web3 ) { setNoWeb3Open ( true ) ; return ; } window . onbeforeunload = ( ) => { return "Your migration is still in progress. Do you really want to leave?" ; } ; setFullLogLines ( [ ] ) ; setMinimalLogLines ( [ ] ) ; onStart ( ) ; const callbacks = getCallbacks ( ) ; setResult ( undefined ) ; createOrganization ( ) ; const result = await migrateDAO ( dao , callbacks ) ; if ( ! result ) return ; let network = await getNetworkName ( ) ; if ( network === 'private' ) { if ( await web3 . eth . net . getId ( ) === 100 ) { network = 'xdai' ; } else if ( await web3 . eth . net . getId ( ) === 77 ) { network = 'sokol' ; } } let url ; if ( network === "mainnet" ) url = `https://alchemy.daostack.io/dao/${ result . Avatar }` ; else if ( network === "rinkeby" ) url = `https://alchemy-staging-rinkeby.herokuapp.com/dao/${ result . Avatar }` ; else if ( network === "xdai" ) url = `https://alchemy-staging-xdai.herokuapp.com/dao/${ result . Avatar }` ; else url = `/dao/${ result . Avatar }` ; setAlchemyURL ( url ) ; onComplete ( result , url ) ; setResult ( result ) ; window . onbeforeunload = ( ) => { } ; } ; const openAlchemy = async ( ) => { if ( ! result ) { console . log ( "Failed to open: Result wasn't set" ) ; return ; } window . open ( alchemyURL ) ; } ; const copyDAOLogs = ( logs ) => { console . log ( JSON . stringify ( JSON . stringify ( logs , null , 2 ) ) ) ; navigator . clipboard . writeText ( JSON . stringify ( logs , null , 2 ) ) ; } ; return installStep !== STEP . Completed ? ( < MDBBtn id = "installButton" disabled = { installStep !== STEP . Waiting && failed === null } onClick = { startInstallation } > { failed === null ? "Install Organization" : "Restart Installation" } < /MDBBtn>) : (<Fragment> < MDBBtn style = { styles . postDeployBtn } onClick = { openAlchemy } > Open Alchemy < /MDBBtn> < MDBBtn style = { styles . postDeployBtn } onClick = { startInstallation } > Redeploy < /MDBBtn> { daoLogs . length > 0 && ( < div style = { { marginLeft : "170px" , marginTop : "12px" } } > < MDBTooltip placement = "top" domElement > < div > < MDBIcon className = "blue-text" size = "lg" icon = "copy" style = { { cursor : "pointer" } } onClick = { ( ) => copyDAOLogs ( daoLogs [ daoLogs . length - 1 ] ) } /> < /div> < div > Click to copy logs < /div> < /MDBTooltip> < /div>)} < /Fragment>); } ; const styles = { postDeployBtn : { fontSize : "13.5px" , padding : "0.65rem" } } ;