@ixily/activ
Version:
Alpha Capture Trade Idea Verification. Blockchain ownership proven trade ideas and strategies.
712 lines (638 loc) • 17.4 kB
text/typescript
import {
ContractModule,
IChain,
id,
ILitProvider,
LogModule as log,
NftStoreModule,
rest,
} from '../..'
// import { ALL_LIT_CHAINS, LIT_CHAINS } from '@lit-protocol/constants'
interface MyContractClients {
chain: IChain
contractAddress: string
encryptionClient: any
actionsClient: any
}
const MAX_LIT_ENC_DEC_ATTEMPTS = 5
const state = {
litProvider: undefined as ILitProvider | undefined,
isBrowser: false as boolean,
contractAddress: '' as string,
chain: 'mainnet' as IChain,
litChainNaming: 'ethereum' as string,
mock: false as boolean,
mockActually: false as boolean,
updating: false as boolean,
contractClients: new Map<string, MyContractClients>(),
gettingAuth: false as boolean,
}
const litNamedChain = (chain: IChain): string => {
// console.log('_+_+_+_+_+_+_+_+_+_+_+_+__+')
// console.log('LIST OF ALL SUPPORTED CHAINS:')
// console.log(ALL_LIT_CHAINS)
// console.log('LIT CHAINS:')
// console.log(LIT_CHAINS)
// console.log('_+_+_+_+_+_+_+_+_+_+_+_+__+')
if ((chain as unknown as string) === 'mainnet') {
return 'ethereum'
}
return chain
}
const config = async (_config: {
litProvider: ILitProvider
mock?: boolean
}) => {
state.litProvider = _config.litProvider
state.isBrowser = _config.litProvider.isBrowser
if (_config.mock !== undefined) {
state.mock = _config.mock
}
ContractModule.getUpdatedStream().subscribe(() => {
updateConfig()
})
await updateConfig()
}
const updateConfig = async () => {
while (state.updating) {
await rest(20)
}
state.updating = true
const contract = ContractModule.getBlockchainContract()
state.chain = contract.recipe.chain
state.litChainNaming = litNamedChain(state.chain)
state.contractAddress = contract.recipe.coreContractAddress
state.mockActually = state.mock
if ((state.chain as unknown as string) === 'hardhat') {
state.mockActually = true
}
if (!state.mockActually) {
if (state.contractClients.get(state.contractAddress) === undefined) {
const encryptionClient =
await state.litProvider!.getEncryptionClient()
const actionsClient = await state.litProvider!.getActionsClient()
state.contractClients.set(state.contractAddress, {
chain: state.chain,
contractAddress: state.contractAddress,
encryptionClient,
actionsClient,
})
}
}
state.updating = false
}
const getEncryptionClient = async (): Promise<any> => {
while (state.contractClients.get(state.contractAddress) === undefined) {
await rest(10)
}
return state.contractClients.get(state.contractAddress)!.encryptionClient
}
const getActionsClient = async (): Promise<any> => {
while (state.contractClients.get(state.contractAddress) === undefined) {
await rest(10)
}
return state.contractClients.get(state.contractAddress)!.actionsClient
}
const setContract = (contractAddress: string) => {
state.contractAddress = contractAddress
}
const accessConditionsOwnId = (tokenId: number): any[] => {
log.dev('state.chain')
log.dev(state.chain)
log.dev('tokenId')
log.dev(tokenId)
const tokenIdStr = tokenId.toString()
const accessControlConditions = [
{
contractAddress: state.contractAddress,
standardContractType: 'ERC1155',
method: 'balanceOf',
parameters: [':userAddress', tokenIdStr],
returnValueTest: {
comparator: '>',
value: '0',
},
chain: state.litChainNaming,
},
]
return accessControlConditions
}
const accessConditionsTemporary = (): any[] => {
const accessControlConditions = [
{
contractAddress: state.contractAddress,
standardContractType: 'ERC1155',
method: 'balanceOf',
parameters: [':userAddress', '0'],
returnValueTest: {
comparator: '>',
value: '0',
},
chain: state.litChainNaming,
},
]
return accessControlConditions
}
const recoverPublicIdeaKeyFromLitForNftId = async (
base64EncryptedString: string,
encryptedSymmetricKey: string,
tokenId: number,
isPublic?: boolean,
// chainToGoBack: IChain,
): Promise<string> => {
if (state.mockActually || isPublic) return base64EncryptedString
await updating()
await getAuthSig()
// log.dev(
// 'recoverPublicIdeaKeyFromLitForNftId (base64EncryptedString)',
// base64EncryptedString,
// )
// log.dev(
// 'recoverPublicIdeaKeyFromLitForNftId (encryptedSymmetricKey)',
// encryptedSymmetricKey,
// )
// log.dev('recoverPublicIdeaKeyFromLitForNftId (tokenId)', tokenId)
let data: any
let accessControlConditions: any[]
// first we try as it was made public
accessControlConditions = accessConditionsOwnId(tokenId)
// console.log('accessControlConditions')
// console.log(accessControlConditions)
// log.dev(
// 'recoverPublicIdeaKeyFromLitForNftId (accessControlConditions)',
// accessControlConditions,
// )
// if (state.networkEnv !== 'local') {
// await makeSureChainMatches(state.networkEnv)
// }
let attempts: number = 0
while (true) {
try {
attempts++
data = await state.litProvider!.recoverString(
await getEncryptionClient(),
base64EncryptedString,
encryptedSymmetricKey,
accessControlConditions,
state.litChainNaming,
)
break
} catch (err: any) {
if (
err.message.indexOf(
'The access control condition check failed. Are you sure you meet the conditions?',
) !== -1
) {
throw err
}
if (
err.message.indexOf(
'The access control conditions you passed in do not match the ones that were set by the condition creator for this encryptedSymmetricKey.',
) !== -1
) {
throw err
}
// 'The access control conditions you passed in do not match the ones that were set by the condition creator for this encryptedSymmetricKey.'
if (attempts > MAX_LIT_ENC_DEC_ATTEMPTS) {
throw err
}
await rest(200)
}
}
// await makeSureChainMatches(chainToGoBack)
// log.dev('recoverPublicIdeaKeyFromLitForNftId (data)', data)
return data
}
const AUTH_SIG_EXPIRATION = 30 * 1000 // 30 seconds
const getAuthSig = async (/*chainToGoBack: IChain*/): Promise<any> => {
if (state.mockActually) return id()
await updating()
while (state.gettingAuth) {
await rest(200)
}
state.gettingAuth = true
// TODO => Fix actually right authSign on Lit Provider to match latest selected wallet
const result = await state.litProvider!.getAuthSig(state.litChainNaming)
state.gettingAuth = false
return result
}
const storePublicIdeaKeyOnLitForNftId = async (
nftId: number,
ideaString: string,
isPublic?: boolean,
// chainToGoBack: IChain,
): Promise<{ encryptedPublicKey: string; encryptedIdea: string }> => {
if (state.mockActually || isPublic)
return { encryptedPublicKey: '' + nftId, encryptedIdea: ideaString }
await updating()
await getAuthSig()
// log.dev('storePublicIdeaKeyOnLitForNftId (nftId)', nftId)
// log.dev('storePublicIdeaKeyOnLitForNftId (ideaString)', ideaString)
const accessControlConditions = accessConditionsOwnId(nftId)
// log.dev(
// 'storePublicIdeaKeyOnLitForNftId (accessControlConditions)',
// accessControlConditions,
// )
// if (state.networkEnv !== 'local') {
// await makeSureChainMatches(state.networkEnv)
// }
const { encryptedString, symmetricKey, authSig } =
await state.litProvider!.encryptString(ideaString, state.litChainNaming)
// log.dev(
// 'storePublicIdeaKeyOnLitForNftId (encryptedString)',
// encryptedString,
// )
// log.dev('storePublicIdeaKeyOnLitForNftId (symmetricKey)', symmetricKey)
// log.dev('storePublicIdeaKeyOnLitForNftId (authSig)', authSig)
const encryptedSymmetricKey = await state.litProvider!.saveKey(
await getEncryptionClient(),
symmetricKey,
accessControlConditions,
authSig,
state.litChainNaming,
)
// await makeSureChainMatches(chainToGoBack)
// log.dev(
// 'storePublicIdeaKeyOnLitForNftId (encryptedSymmetricKey)',
// encryptedSymmetricKey.encryptedSymmetricKeyString,
// )
const obj = {
encryptedPublicKey: encryptedSymmetricKey.encryptedSymmetricKeyString,
encryptedIdea: encryptedString,
}
// log.dev('storePublicIdeaKeyOnLitForNftId (obj)', obj)
return obj
}
const storeTemporaryPublicIdeaKeyOnLit = async (
ideaString: string,
isPublic?: boolean,
// chainToGoBack: IChain,
): Promise<{
encryptedPublicKey: string
encryptedSymetricKeyRaw: string
symmetricKey: string
encryptedIdea: string
authSig: any
}> => {
if (state.mockActually || isPublic) {
const rId = id()
return {
encryptedPublicKey: rId,
encryptedSymetricKeyRaw: rId,
symmetricKey: rId,
encryptedIdea: ideaString,
authSig: rId,
}
}
await updating()
await getAuthSig()
// log.dev('storePublicIdeaKeyOnLitForNftId (ideaString)', ideaString)
const accessControlConditions = accessConditionsTemporary()
// log.dev(
// 'storePublicIdeaKeyOnLitForNftId (accessControlConditions)',
// accessControlConditions,
// )
// if (state.networkEnv !== 'local') {
// await makeSureChainMatches(state.networkEnv)
// }
const { encryptedString, symmetricKey, authSig } =
await state.litProvider!.encryptString(ideaString, state.litChainNaming)
// log.dev(
// 'storePublicIdeaKeyOnLitForNftId (encryptedString)',
// encryptedString,
// )
// log.dev('storePublicIdeaKeyOnLitForNftId (symmetricKey)', symmetricKey)
// log.dev('storePublicIdeaKeyOnLitForNftId (authSig)', authSig)
const saveKeyData = await state.litProvider!.saveKey(
await getEncryptionClient(),
symmetricKey,
accessControlConditions,
authSig,
state.litChainNaming,
false, // permanent: false,
)
// await makeSureChainMatches(chainToGoBack)
// log.dev(
// 'storePublicIdeaKeyOnLitForNftId (encryptedSymmetricKey)',
// saveKeyData.encryptedSymmetricKeyString,
// )
const obj = {
symmetricKey,
encryptedPublicKey: saveKeyData.encryptedSymmetricKeyString,
encryptedSymetricKeyRaw: saveKeyData.encryptedSymmetricKey,
encryptedIdea: encryptedString,
authSig,
}
// log.dev('storePublicIdeaKeyOnLitForNftId (obj)', obj)
return obj
}
const updateToDefinitiveAccessControlConditions = async (
encryptedSymmetricKey: string,
symmetricKey: string,
nftId: number,
authSig: any,
isPublic?: boolean,
) => {
// log.dev(
// 'updateToDefinitiveAccessControlConditions (state.mock)',
// state.mock,
// )
if (state.mock || isPublic) return
await updating()
await getAuthSig()
// log.dev(
// 'updateToDefinitiveAccessControlConditions (symmetricKey)',
// symmetricKey,
// )
const accessControlConditions = accessConditionsOwnId(nftId)
// log.dev(
// 'updateToDefinitiveAccessControlConditions (accessControlConditions)',
// accessControlConditions,
// )
// log.dev('updateToDefinitiveAccessControlConditions (authSig)', authSig)
// if (state.networkEnv !== 'local') {
// await makeSureChainMatches(state.networkEnv)
// }
let attempts: number = 0
const updtACC = async () => {
// authSig = await getAuthSig()
await state.litProvider!.updateConditionsKey(
await getEncryptionClient(),
encryptedSymmetricKey,
symmetricKey,
accessControlConditions,
authSig,
state.litChainNaming,
true,
)
}
while (true) {
try {
attempts++
await updtACC()
break
} catch (e) {
console.log(
'LitModule: Error on updateToDefinitiveAccessControlConditions',
)
// 'The access control conditions you passed in do not match the ones that were set by the condition creator for this encryptedSymmetricKey.'
if (attempts > MAX_LIT_ENC_DEC_ATTEMPTS) {
throw e
}
await rest(500)
}
}
// await makeSureChainMatches(chainToGoBack)
}
/*
export const runJSFallback = async <T>(
javascriptCode: string,
params: any,
): Promise<{
response: T
}> => {
if (state.mock) return runJSFallbackMock<T>(javascriptCode, params)
// if (state.networkEnv !== 'local' && state.networkEnv !== chainToGoBack) {
// await makeSureChainMatches(state.networkEnv)
// }
const litActionResponse = await state.litProvider!.runJSFallback<T>(
javascriptCode,
params,
state.litChainNaming,
)
// await makeSureChainMatches(chainToGoBack)
// log.dev('runJS (litActionResponse)', litActionResponse)
// your global sign here...
return litActionResponse
}
*/
// testId => 105513016513708266538432932353309329163187878127577176348882795059994013308295
// testEth => 0x2c0b39760f91F60f1777F8269227Fc9A073a1659
// testPubKey => 0x04386cab00b0cbe7da91e445a1f305d84d1017d974f6316f8c397c36ff5d07a688a7ed1c737ea9b615b462d3909e2aa52cf48ee6318f6284cc94a96822d43d2333
const testJS = async (): Promise<{
results: Array<{
result: 'success' | 'failure'
nodes: number
response?: any
error?: any
}>
success: boolean
minForSuccess: number
maximumNodes: number
workingNodes: number
}> => {
await updating()
const ipfsId = 'QmSCxGRRznNDJRDri9qd3batstNiSj9xDHRTVhj8j2TKfo'
const publicKey =
'0x04386cab00b0cbe7da91e445a1f305d84d1017d974f6316f8c397c36ff5d07a688a7ed1c737ea9b615b462d3909e2aa52cf48ee6318f6284cc94a96822d43d2333'
const results: Array<{
result: 'success' | 'failure'
nodes: number
response?: any
error?: any
}> = []
const maximumNodes = 10
const minForSuccess = 7
let nodes: number = maximumNodes
const genResultForNodes = async (nodes: number) => {
return runJS(ipfsId, publicKey, undefined, nodes)
.then((response) => {
return {
result: 'success' as 'success',
nodes,
response,
}
})
.catch((error) => {
return {
result: 'failure' as 'failure',
nodes,
error,
}
})
}
results.push(await genResultForNodes(maximumNodes))
while (results[results.length - 1].result === 'failure' && nodes > 0) {
nodes--
results.push(await genResultForNodes(nodes))
}
const finalResult = {
results,
success: nodes >= minForSuccess,
minForSuccess,
maximumNodes,
workingNodes: nodes,
}
return finalResult
}
export const runJS = async (
ipfsId: string,
publicKey: string,
params?: any,
nodes: number = 10,
): Promise<any> => {
// console.log('state.mock:')
// console.log(state.mock)
if (state.mock) return runJSMock(ipfsId, publicKey, params)
await updating()
await getAuthSig()
// if (state.networkEnv !== 'local' && state.networkEnv !== chainToGoBack) {
// await makeSureChainMatches(state.networkEnv)
// }
// log.dev('Lit Module: runJS: ipfsId: ', ipfsId)
// log.dev('Lit Module: runJS: publicKey: ', publicKey)
// log.dev('Lit Module: runJS: nodes: ', nodes)
const litActionResponse = await state.litProvider!.runJS(
await getActionsClient(),
ipfsId,
publicKey,
state.litChainNaming,
params,
nodes,
)
// await makeSureChainMatches(chainToGoBack)
// log.dev('runJS (litActionResponse)', litActionResponse)
// your global sign here...
return litActionResponse
}
const runJSFallbackMock = async <T>(
javascriptCode: string,
params: any,
): Promise<{
response: T
}> => {
let addParams = ''
for (const param in params) {
addParams += `let ${param} = ${
params[param] === undefined
? 'undefined'
: typeof params[param] === 'string'
? `'${params[param]}'`
: typeof params[param] === 'object'
? JSON.stringify(params[param])
: params[param]
};
`
}
const masterFunctionStart =
(state.isBrowser
? ''
: `const fetch = require('isomorphic-fetch');
`) +
`
const ethers = {
utils: {
toUtf8Bytes: (value) => {
return value
},
keccak256: (value) => {
return value
}
}
}
async function masterFunction() {
let resolvedMaster = false;
let state = {
response: null,
signatures: {}
}
const LitActions = {
setResponse: (response) => {
state = {
...state,
...response
}
resolvedMaster = true
},
ethPersonalSignMessageEcdsa: (
message,
publicKey,
sigName,
) => {
state.signatures = {}
}
}
const asyncCalledFunction = async () => {
`
const masterFunctionEnd = `
}
let error = undefined
asyncCalledFunction().catch((e) => {
error = e
})
while(!resolvedMaster && error === undefined ) {
console.log('error', error)
await new Promise((resolve) => setTimeout(resolve, 1000))
}
if(error !== undefined) {
throw error
}
return state;
}
masterFunction()
`
const code =
masterFunctionStart +
addParams +
javascriptCode.replace('go()', 'await go()') +
masterFunctionEnd
const codeEscaped = code.replace(/'\n'/g, "'\\n'")
try {
// console.log('what is going on?')
// console.log(codeEscaped)
const resultRaw = await eval(codeEscaped)
const result = resultRaw as { response: string }
log.dev('result:')
log.dev(result)
const resultResponse = {
...result,
response: JSON.parse(result.response) as T,
}
return resultResponse
} catch (e) {
log.dev('Error on mock lit action:')
log.dev(e)
throw e
}
}
const runJSMock = async <T>(
ipfsId: string,
publicKey: string,
params: any,
): Promise<{
signatures: any
response: T
logs: string[]
}> => {
log.dev('https://ipfs.io/ipfs/' + ipfsId)
const url = 'https://ipfs.io/ipfs/' + ipfsId
const codeString = await NftStoreModule.getJsonContent(url, {
forceIPFSdirectly: true,
})
log.dev('codeString:')
log.dev(codeString)
params['publicKey'] = publicKey
const responseResult = await runJSFallbackMock<T>(codeString, params)
return {
...responseResult,
signatures: {},
logs: [],
}
}
const updating = async () => {
while (state.updating) {
await rest(20)
}
}
export const LitModule = {
config,
setContract,
getAuthSig,
storePublicIdeaKeyOnLitForNftId,
storeTemporaryPublicIdeaKeyOnLit,
updateToDefinitiveAccessControlConditions,
recoverPublicIdeaKeyFromLitForNftId,
// runJSFallback,
runJS,
testJS,
}