Skip to content

Commit

Permalink
Merge pull request #512 from openworklabs/dev
Browse files Browse the repository at this point in the history
* Feat/msig staging (#501)

* Add initial framework for withdrawing multisig funds and changing multisig owners

Co-authored-by: Alex Singh <[email protected]>

* Feat/fix account info484 (#504)

Close #484

* Replace Withdraw flow fixed footer w/ flex-based sticky footer (#507)

Remove flxed positioned send flow elements in msig

* Enable premainnet saft flow to work w/out a node (#503)

* Enable premainnet saft flow to work w/out a node

* Add more tests for onboarding and premainnet saft support

* Add checks for bad actors (#505)

* Fix available balance showing the inverse avail

* First take at send flow refactor, working (#509)

* Refactor send flow to fit multisig flow (#509)
* Improve send flow user experience

Co-authored-by: Alex Singh <[email protected]>

* Fix #497 (#511)

* Bump version

Co-authored-by: Alex Singh <[email protected]>
  • Loading branch information
Schwartz10 and as-dr authored Sep 11, 2020
2 parents b4752d7 + 3ecf9dd commit e2ca474
Show file tree
Hide file tree
Showing 71 changed files with 15,768 additions and 3,977 deletions.
80 changes: 80 additions & 0 deletions MsigProvider/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { useEffect, useState } from 'react'
import { FilecoinNumber } from '@openworklabs/filecoin-number'
import LotusRPCEngine from '@openworklabs/lotus-jsonrpc-engine'
import { useRouter } from 'next/router'
import { useWalletProvider } from '../WalletProvider'
import useWallet from '../WalletProvider/useWallet'
import reportError from '../utils/reportError'
import isAddressSigner from './isAddressSigner'
import isActorMsig from './isActorMsig'

const emptyActorState = {
Balance: new FilecoinNumber('0', 'fil'),
AvailableBalance: new FilecoinNumber('0', 'fil')
}

// Taking a small shortcut here for now, this hook should only be called once per msig
export const useMsig = msigActorID => {
const wallet = useWallet()
const { walletProvider } = useWalletProvider()
const [actorState, setActorState] = useState(null)
const router = useRouter()

useEffect(() => {
const fetchActorState = async () => {
const lotus = new LotusRPCEngine({
apiAddress: process.env.LOTUS_NODE_JSONRPC
})
try {
const { Balance, State } = await lotus.request(
'StateReadState',
msigActorID,
null
)

if (!isActorMsig(State)) {
router.push('/error/not-a-multisig')
}

if (!(await isAddressSigner(lotus, wallet.address, State?.Signers))) {
const params = new URLSearchParams(router.query)
params.set('walletAddress', wallet.address)
params.set('msigAddress', msigActorID)
router.push(`/error/not-a-signer?${params.toString()}`)
}

// confusing - MsigGetAval returns locked, not avail see https://github.com/filecoin-project/lotus/issues/3699
const lockedBal = await lotus.request(
'MsigGetAvailableBalance',
msigActorID,
null
)

const balance = new FilecoinNumber(Balance, 'attofil')

const nextState = {
Balance: balance,
AvailableBalance: balance.minus(
new FilecoinNumber(lockedBal, 'attofil')
),
...State
}
setActorState(nextState)
} catch (err) {
reportError(22, true, err.message, err.stack)
}
}
if (!actorState && msigActorID) {
fetchActorState()
}
}, [
actorState,
msigActorID,
setActorState,
walletProvider,
router,
wallet.address
])
if (!actorState) return emptyActorState
return { Address: msigActorID, ...actorState }
}
3 changes: 3 additions & 0 deletions MsigProvider/isActorMsig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default state => {
return !!state?.Signers
}
12 changes: 12 additions & 0 deletions MsigProvider/isActorMsig.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import isActorMsig from './isActorMsig'

describe('isActorMsig', () => {
test('it returns true for states that have Signers prop', () => {
expect(isActorMsig({ Signers: ['t01001'] })).toBe(true)
})

test('it returns false for states that have no Signers prop', () => {
expect(isActorMsig({ Signes: ['t01001'] })).toBe(false)
expect(isActorMsig({})).toBe(false)
})
})
14 changes: 14 additions & 0 deletions MsigProvider/isAddressSigner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default async (lotus, walletAddress, signers) => {
let idAddress = ''

try {
idAddress = await lotus.request('StateLookupID', walletAddress, null)
} catch (_) {
// noop
}

return signers.some(signer => {
if (signer[1] === '0') return signer === idAddress
return signer === walletAddress
})
}
46 changes: 46 additions & 0 deletions MsigProvider/isAddressSigner.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import isAddressSigner from './isAddressSigner'

describe('isAddressSigner', () => {
let lotus

afterEach(() => {
jest.clearAllMocks()
lotus = {
request: jest.fn(() => {
return Promise.resolve('t0100')
})
}
})

test('it confirms non ID address signers', async () => {
const walletAddress = 't137sjdbgunloi7couiy4l5nc7pd6k2jmq32vizpy'
const signers = ['t137sjdbgunloi7couiy4l5nc7pd6k2jmq32vizpy']
expect(await isAddressSigner(lotus, walletAddress, signers)).toBe(true)
signers.push('t137sjdbgunloi7couiy4l5nc7pd6k2jmq32vidpy')
signers.push('t137sjdbgunloi7couiy4l5dsafdsak2jmq32vidpy')
expect(await isAddressSigner(lotus, walletAddress, signers)).toBe(true)
})

test('it rejects non ID address signers', async () => {
const walletAddress = 't137sjdbgunloi7couiy4l5nc7pd6k2jmq32vizty'
const signers = ['t137sjdbgunloi7couiy4l5nc7pd6k2jmq32vizpy']
expect(await isAddressSigner(lotus, walletAddress, signers)).toBe(false)
signers.push('t137sjdbgunloi7couiy4l5nc7pd6k2jmq32vidpy')
signers.push('t137sjdbgunloi7couiy4l5dsafdsak2jmq32vidpy')
expect(await isAddressSigner(lotus, walletAddress, signers)).toBe(false)
})

test('it accepts ID address signers', async () => {
const walletAddress = 't137sjdbgunloi7couiy4l5nc7pd6k2jmq32vizty'
const signers = ['t0100', 't01002']
expect(await isAddressSigner(lotus, walletAddress, signers)).toBe(true)
expect(await isAddressSigner(lotus, 't0100', signers)).toBe(true)
})

test('it rejects ID address signers', async () => {
const walletAddress = 't137sjdbgunloi7couiy4l5nc7pd6k2jmq32vizty'
const signers = ['t01001', 't01002']
expect(await isAddressSigner(lotus, walletAddress, signers)).toBe(false)
expect(await isAddressSigner(lotus, 't0100', signers)).toBe(false)
})
})
30 changes: 21 additions & 9 deletions components/AccountSelector/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const Close = styled(ButtonClose)`
right: ${props => props.theme.sizes[3]}px;
`

const AccountSelector = ({ premainnetInvestor }) => {
const AccountSelector = ({ premainnetInvestor, msig }) => {
const wallet = useWallet()
const [loadingAccounts, setLoadingAccounts] = useState(false)
const [loadingPage, setLoadingPage] = useState(true)
Expand Down Expand Up @@ -128,9 +128,10 @@ const AccountSelector = ({ premainnetInvestor }) => {

const onClose = () => {
const searchParams = new URLSearchParams(router.query)
const route = premainnetInvestor
? `/vault/home?${searchParams.toString()}`
: `/home?${searchParams.toString()}`
let route = ''
if (premainnetInvestor) route = `/vault/home?${searchParams.toString()}`
else if (msig) route = `/msig/choose?${searchParams.toString()}`
else route = `/home?${searchParams.toString()}`
router.push(route)
}

Expand Down Expand Up @@ -198,16 +199,25 @@ const AccountSelector = ({ premainnetInvestor }) => {
color='core.white'
/>
<Title ml={2}>
{premainnetInvestor ? 'Select Account' : 'Switch Accounts'}
{premainnetInvestor || msig
? 'Select Account'
: 'Switch Accounts'}
</Title>
</MenuItem>
<MenuItem>
{premainnetInvestor ? (
{premainnetInvestor && (
<Text>
Please select the Ledger account you wish to own and sign
for your multisig investor wallet.
</Text>
) : (
)}
{msig && (
<Text>
Please select the Ledger account that owns your multisig
investor wallet.
</Text>
)}
{!premainnetInvestor && !msig && (
<Text>
Your single{' '}
{wallet.type === LEDGER ? 'Ledger Device ' : 'seed phrase'}{' '}
Expand Down Expand Up @@ -247,11 +257,13 @@ const AccountSelector = ({ premainnetInvestor }) => {
}

AccountSelector.propTypes = {
premainnetInvestor: bool
premainnetInvestor: bool,
msig: bool
}

AccountSelector.defaultProps = {
premainnetInvestor: false
premainnetInvestor: false,
msig: false
}

export default AccountSelector
2 changes: 2 additions & 0 deletions components/Investor/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,15 @@ const PreConfirm = ({ address, investor, path }) => {
<Input.Text
value={investor}
onChange={noop}
placeholder='InvestorID'
label='InvestorID'
disabled
/>
<Box display='flex' flexDirection='column' alignItems='flex-start'>
<Input.Text
value={address}
onChange={noop}
placeholder='Filecoin address'
label='Filecoin address'
disabled
/>
Expand Down
2 changes: 1 addition & 1 deletion components/Investor/InvestorOnboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default () => {
padding={[2, 3, 5]}
>
{investor ? (
<Ledger investor />
<Ledger premainnetInvestor />
) : (
<EnterId setWalletType={setWalletType} />
)}
Expand Down
Loading

0 comments on commit e2ca474

Please sign in to comment.